home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / gfx / conv / ffmpeg-source.lha / ffmpeg.COURCE / ffserver.c < prev    next >
C/C++ Source or Header  |  2002-06-10  |  87KB  |  2,661 lines

  1. /*
  2.  * Multiple format streaming server
  3.  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
  4.  *
  5.  * This library is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU Lesser General Public
  7.  * License as published by the Free Software Foundation; either
  8.  * version 2 of the License, or (at your option) any later version.
  9.  *
  10.  * This library is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.  * Lesser General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU Lesser General Public
  16.  * License along with this library; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  */
  19. #define HAVE_AV_CONFIG_H
  20. #include "avformat.h"
  21.  
  22. #include <stdarg.h>
  23. #include <netinet/in.h>
  24. #include <unistd.h>
  25. #include <fcntl.h>
  26. #include <sys/ioctl.h>
  27. #include <sys/poll.h>
  28. #include <errno.h>
  29. #include <sys/time.h>
  30. #include <time.h>
  31. #include <getopt.h>
  32. #include <sys/types.h>
  33. #include <sys/socket.h>
  34. #include <sys/wait.h>
  35. #include <arpa/inet.h>
  36. #include <netdb.h>
  37. #include <ctype.h>
  38. #include <signal.h>
  39.  
  40. /* maximum number of simultaneous HTTP connections */
  41. #define HTTP_MAX_CONNECTIONS 2000
  42.  
  43. enum HTTPState {
  44.     HTTPSTATE_WAIT_REQUEST,
  45.     HTTPSTATE_SEND_HEADER,
  46.     HTTPSTATE_SEND_DATA_HEADER,
  47.     HTTPSTATE_SEND_DATA,
  48.     HTTPSTATE_SEND_DATA_TRAILER,
  49.     HTTPSTATE_RECEIVE_DATA,
  50.     HTTPSTATE_WAIT_FEED,
  51. };
  52.  
  53. const char *http_state[] = {
  54.     "WAIT_REQUEST",
  55.     "SEND_HEADER",
  56.     "SEND_DATA_HEADER",
  57.     "SEND_DATA",
  58.     "SEND_DATA_TRAILER",
  59.     "RECEIVE_DATA",
  60.     "WAIT_FEED",
  61. };
  62.  
  63. #define IOBUFFER_INIT_SIZE 8192
  64. #define PBUFFER_INIT_SIZE 8192
  65.  
  66. /* coef for exponential mean for bitrate estimation in statistics */
  67. #define AVG_COEF 0.9
  68.  
  69. /* timeouts are in ms */
  70. #define REQUEST_TIMEOUT (15 * 1000)
  71. #define SYNC_TIMEOUT (10 * 1000)
  72.  
  73. typedef struct {
  74.     INT64 count1, count2;
  75.     long time1, time2;
  76. } DataRateData;
  77.  
  78. /* context associated with one connection */
  79. typedef struct HTTPContext {
  80.     enum HTTPState state;
  81.     int fd; /* socket file descriptor */
  82.     struct sockaddr_in from_addr; /* origin */
  83.     struct pollfd *poll_entry; /* used when polling */
  84.     long timeout;
  85.     UINT8 *buffer_ptr, *buffer_end;
  86.     int http_error;
  87.     struct HTTPContext *next;
  88.     int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
  89.     INT64 data_count;
  90.     /* feed input */
  91.     int feed_fd;
  92.     /* input format handling */
  93.     AVFormatContext *fmt_in;
  94.     /* output format handling */
  95.     struct FFStream *stream;
  96.     /* -1 is invalid stream */
  97.     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
  98.     int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
  99.     int switch_pending;
  100.     AVFormatContext fmt_ctx;
  101.     int last_packet_sent; /* true if last data packet was sent */
  102.     int suppress_log;
  103.     int bandwidth;
  104.     long start_time;            /* In milliseconds - this wraps fairly often */
  105.     DataRateData datarate;
  106.     int wmp_client_id;
  107.     char protocol[16];
  108.     char method[16];
  109.     char url[128];
  110.     int buffer_size;
  111.     UINT8 *buffer;
  112.     int pbuffer_size;
  113.     UINT8 *pbuffer;
  114. } HTTPContext;
  115.  
  116. /* each generated stream is described here */
  117. enum StreamType {
  118.     STREAM_TYPE_LIVE,
  119.     STREAM_TYPE_STATUS,
  120.     STREAM_TYPE_REDIRECT,
  121. };
  122.  
  123. /* description of each stream of the ffserver.conf file */
  124. typedef struct FFStream {
  125.     enum StreamType stream_type;
  126.     char filename[1024];     /* stream filename */
  127.     struct FFStream *feed;
  128.     AVOutputFormat *fmt;
  129.     int nb_streams;
  130.     int prebuffer;      /* Number of millseconds early to start */
  131.     long max_time;      /* Number of milliseconds to run */
  132.     int send_on_key;
  133.     AVStream *streams[MAX_STREAMS];
  134.     int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
  135.     char feed_filename[1024]; /* file name of the feed storage, or
  136.                                  input file name for a stream */
  137.     char author[512];
  138.     char title[512];
  139.     char copyright[512];
  140.     char comment[512];
  141.     pid_t pid;  /* Of ffmpeg process */
  142.     time_t pid_start;  /* Of ffmpeg process */
  143.     char **child_argv;
  144.     struct FFStream *next;
  145.     /* feed specific */
  146.     int feed_opened;     /* true if someone if writing to feed */
  147.     int is_feed;         /* true if it is a feed */
  148.     int conns_served;
  149.     INT64 bytes_served;
  150.     INT64 feed_max_size;      /* maximum storage size */
  151.     INT64 feed_write_index;   /* current write position in feed (it wraps round) */
  152.     INT64 feed_size;          /* current size of feed */
  153.     struct FFStream *next_feed;
  154. } FFStream;
  155.  
  156. typedef struct FeedData {
  157.     long long data_count;
  158.     float avg_frame_size;   /* frame size averraged over last frames with exponential mean */
  159. } FeedData;
  160.  
  161. struct sockaddr_in my_addr;
  162. char logfilename[1024];
  163. HTTPContext *first_http_ctx;
  164. FFStream *first_feed;   /* contains only feeds */
  165. FFStream *first_stream; /* contains all streams, including feeds */
  166.  
  167. static int handle_http(HTTPContext *c);
  168. static int http_parse_request(HTTPContext *c);
  169. static int http_send_data(HTTPContext *c);
  170. static void compute_stats(HTTPContext *c);
  171. static int open_input_stream(HTTPContext *c, const char *info);
  172. static int http_start_receive_data(HTTPContext *c);
  173. static int http_receive_data(HTTPContext *c);
  174.  
  175. static const char *my_program_name;
  176.  
  177. static int ffserver_debug;
  178. static int no_launch;
  179. static int need_to_start_children;
  180.  
  181. int nb_max_connections;
  182. int nb_connections;
  183.  
  184. int nb_max_bandwidth;
  185. int nb_bandwidth;
  186.  
  187. static long cur_time;           // Making this global saves on passing it around everywhere
  188.  
  189. static long gettime_ms(void)
  190. {
  191.     struct timeval tv;
  192.  
  193.     gettimeofday(&tv,NULL);
  194.     return (long long)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
  195. }
  196.  
  197. static FILE *logfile = NULL;
  198.  
  199. static void http_log(char *fmt, ...)
  200. {
  201.     va_list ap;
  202.     va_start(ap, fmt);
  203.     
  204.     if (logfile) {
  205.         vfprintf(logfile, fmt, ap);
  206.         fflush(logfile);
  207.     }
  208.     va_end(ap);
  209. }
  210.  
  211. static void log_connection(HTTPContext *c)
  212. {
  213.     char buf1[32], buf2[32], *p;
  214.     time_t ti;
  215.  
  216.     if (c->suppress_log) 
  217.         return;
  218.  
  219.     /* XXX: reentrant function ? */
  220.     p = inet_ntoa(c->from_addr.sin_addr);
  221.     strcpy(buf1, p);
  222.     ti = time(NULL);
  223.     p = ctime(&ti);
  224.     strcpy(buf2, p);
  225.     p = buf2 + strlen(p) - 1;
  226.     if (*p == '\n')
  227.         *p = '\0';
  228.     http_log("%s - - [%s] \"%s %s %s\" %d %lld\n", 
  229.              buf1, buf2, c->method, c->url, c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
  230. }
  231.  
  232. static void update_datarate(DataRateData *drd, INT64 count)
  233. {
  234.     if (!drd->time1 && !drd->count1) {
  235.         drd->time1 = drd->time2 = cur_time;
  236.         drd->count1 = drd->count2 = count;
  237.     } else {
  238.         if (cur_time - drd->time2 > 5000) {
  239.             drd->time1 = drd->time2;
  240.             drd->count1 = drd->count2;
  241.             drd->time2 = cur_time;
  242.             drd->count2 = count;
  243.         }
  244.     }
  245. }
  246.  
  247. /* In bytes per second */
  248. static int compute_datarate(DataRateData *drd, INT64 count)
  249. {
  250.     if (cur_time == drd->time1)
  251.         return 0;
  252.  
  253.     return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
  254. }
  255.  
  256. static void start_children(FFStream *feed)
  257. {
  258.     if (no_launch)
  259.         return;
  260.  
  261.     for (; feed; feed = feed->next) {
  262.         if (feed->child_argv && !feed->pid) {
  263.             feed->pid_start = time(0);
  264.  
  265.             feed->pid = fork();
  266.  
  267.             if (feed->pid < 0) {
  268.                 fprintf(stderr, "Unable to create children\n");
  269.                 exit(1);
  270.             }
  271.             if (!feed->pid) {
  272.                 /* In child */
  273.                 char pathname[1024];
  274.                 char *slash;
  275.                 int i;
  276.  
  277.                 for (i = 3; i < 256; i++) {
  278.                     close(i);
  279.                 }
  280.  
  281.                 if (!ffserver_debug) {
  282.                     i = open("/dev/null", O_RDWR);
  283.                     if (i)
  284.                         dup2(i, 0);
  285.                     dup2(i, 1);
  286.                     dup2(i, 2);
  287.                     if (i)
  288.                         close(i);
  289.                 }
  290.  
  291.                 pstrcpy(pathname, sizeof(pathname), my_program_name);
  292.  
  293.                 slash = strrchr(pathname, '/');
  294.                 if (!slash) {
  295.                     slash = pathname;
  296.                 } else {
  297.                     slash++;
  298.                 }
  299.                 strcpy(slash, "ffmpeg");
  300.  
  301.                 execvp(pathname, feed->child_argv);
  302.  
  303.                 _exit(1);
  304.             }
  305.         }
  306.     }
  307. }
  308.  
  309. /* main loop of the http server */
  310. static int http_server(struct sockaddr_in my_addr)
  311. {
  312.     int server_fd, tmp, ret;
  313.     struct sockaddr_in from_addr;
  314.     struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 1], *poll_entry;
  315.     HTTPContext *c, **cp;
  316.  
  317.     server_fd = socket(AF_INET,SOCK_STREAM,0);
  318.     if (server_fd < 0) {
  319.         perror ("socket");
  320.         return -1;
  321.     }
  322.         
  323.     tmp = 1;
  324.     setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
  325.  
  326.     if (bind (server_fd, (struct sockaddr *) &my_addr, sizeof (my_addr)) < 0) {
  327.         perror ("bind");
  328.         close(server_fd);
  329.         return -1;
  330.     }
  331.   
  332.     if (listen (server_fd, 5) < 0) {
  333.         perror ("listen");
  334.         close(server_fd);
  335.         return -1;
  336.     }
  337.  
  338.     http_log("ffserver started.\n");
  339.  
  340.     start_children(first_feed);
  341.  
  342.     fcntl(server_fd, F_SETFL, O_NONBLOCK);
  343.     first_http_ctx = NULL;
  344.     nb_connections = 0;
  345.     first_http_ctx = NULL;
  346.     for(;;) {
  347.         poll_entry = poll_table;
  348.         poll_entry->fd = server_fd;
  349.         poll_entry->events = POLLIN;
  350.         poll_entry++;
  351.  
  352.         /* wait for events on each HTTP handle */
  353.         c = first_http_ctx;
  354.         while (c != NULL) {
  355.             int fd;
  356.             fd = c->fd;
  357.             switch(c->state) {
  358.             case HTTPSTATE_WAIT_REQUEST:
  359.                 c->poll_entry = poll_entry;
  360.                 poll_entry->fd = fd;
  361.                 poll_entry->events = POLLIN;
  362.                 poll_entry++;
  363.                 break;
  364.             case HTTPSTATE_SEND_HEADER:
  365.             case HTTPSTATE_SEND_DATA_HEADER:
  366.             case HTTPSTATE_SEND_DATA:
  367.             case HTTPSTATE_SEND_DATA_TRAILER:
  368.                 c->poll_entry = poll_entry;
  369.                 poll_entry->fd = fd;
  370.                 poll_entry->events = POLLOUT;
  371.                 poll_entry++;
  372.                 break;
  373.             case HTTPSTATE_RECEIVE_DATA:
  374.                 c->poll_entry = poll_entry;
  375.                 poll_entry->fd = fd;
  376.                 poll_entry->events = POLLIN;
  377.                 poll_entry++;
  378.                 break;
  379.             case HTTPSTATE_WAIT_FEED:
  380.                 /* need to catch errors */
  381.                 c->poll_entry = poll_entry;
  382.                 poll_entry->fd = fd;
  383.                 poll_entry->events = POLLIN;/* Maybe this will work */
  384.                 poll_entry++;
  385.                 break;
  386.             default:
  387.                 c->poll_entry = NULL;
  388.                 break;
  389.             }
  390.             c = c->next;
  391.         }
  392.  
  393.         /* wait for an event on one connection. We poll at least every
  394.            second to handle timeouts */
  395.         do {
  396.             ret = poll(poll_table, poll_entry - poll_table, 1000);
  397.         } while (ret == -1);
  398.         
  399.         cur_time = gettime_ms();
  400.  
  401.         if (need_to_start_children) {
  402.             need_to_start_children = 0;
  403.             start_children(first_feed);
  404.         }
  405.  
  406.         /* now handle the events */
  407.  
  408.         cp = &first_http_ctx;
  409.         while ((*cp) != NULL) {
  410.             c = *cp;
  411.             if (handle_http (c) < 0) {
  412.                 /* close and free the connection */
  413.                 log_connection(c);
  414.                 close(c->fd);
  415.                 if (c->fmt_in)
  416.                     av_close_input_file(c->fmt_in);
  417.                 *cp = c->next;
  418.                 nb_bandwidth -= c->bandwidth;
  419.                 av_free(c->buffer);
  420.                 av_free(c->pbuffer);
  421.                 av_free(c);
  422.                 nb_connections--;
  423.             } else {
  424.                 cp = &c->next;
  425.             }
  426.         }
  427.  
  428.         /* new connection request ? */
  429.         poll_entry = poll_table;
  430.         if (poll_entry->revents & POLLIN) {
  431.             int fd, len;
  432.  
  433.             len = sizeof(from_addr);
  434.             fd = accept(server_fd, (struct sockaddr *)&from_addr, 
  435.                         &len);
  436.             if (fd >= 0) {
  437.                 fcntl(fd, F_SETFL, O_NONBLOCK);
  438.                 /* XXX: should output a warning page when coming
  439.                    close to the connection limit */
  440.                 if (nb_connections >= nb_max_connections) {
  441.                     c = NULL;
  442.                 } else {
  443.                     /* add a new connection */
  444.                     c = av_mallocz(sizeof(HTTPContext));
  445.                     if (c) {
  446.                         c->next = first_http_ctx;
  447.                         first_http_ctx = c;
  448.                         c->fd = fd;
  449.                         c->poll_entry = NULL;
  450.                         c->from_addr = from_addr;
  451.                         c->state = HTTPSTATE_WAIT_REQUEST;
  452.                         c->buffer = av_malloc(c->buffer_size = IOBUFFER_INIT_SIZE);
  453.                         c->pbuffer = av_malloc(c->pbuffer_size = PBUFFER_INIT_SIZE);
  454.                         if (!c->buffer || !c->pbuffer) {
  455.                             av_free(c->buffer);
  456.                             av_free(c->pbuffer);
  457.                             av_freep(&c);
  458.                         } else {
  459.                             c->buffer_ptr = c->buffer;
  460.                             c->buffer_end = c->buffer + c->buffer_size;
  461.                             c->timeout = cur_time + REQUEST_TIMEOUT;
  462.                             c->start_time = cur_time;
  463.                             nb_connections++;
  464.                         }
  465.                     }
  466.                 }
  467.                 if (!c) {
  468.                     close(fd);
  469.                 }
  470.             }
  471.         }
  472.         poll_entry++;
  473.     }
  474. }
  475.  
  476. static int handle_http(HTTPContext *c)
  477. {
  478.     int len;
  479.     
  480.     switch(c->state) {
  481.     case HTTPSTATE_WAIT_REQUEST:
  482.         /* timeout ? */
  483.         if ((c->timeout - cur_time) < 0)
  484.             return -1;
  485.         if (c->poll_entry->revents & (POLLERR | POLLHUP))
  486.             return -1;
  487.  
  488.         /* no need to read if no events */
  489.         if (!(c->poll_entry->revents & POLLIN))
  490.             return 0;
  491.         /* read the data */
  492.         len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
  493.         if (len < 0) {
  494.             if (errno != EAGAIN && errno != EINTR)
  495.                 return -1;
  496.         } else if (len == 0) {
  497.             return -1;
  498.         } else {
  499.             /* search for end of request. XXX: not fully correct since garbage could come after the end */
  500.             UINT8 *ptr;
  501.             c->buffer_ptr += len;
  502.             ptr = c->buffer_ptr;
  503.             if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
  504.                 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
  505.                 /* request found : parse it and reply */
  506.                 if (http_parse_request(c) < 0)
  507.                     return -1;
  508.             } else if (ptr >= c->buffer_end) {
  509.                 /* request too long: cannot do anything */
  510.                 return -1;
  511.             }
  512.         }
  513.         break;
  514.  
  515.     case HTTPSTATE_SEND_HEADER:
  516.         if (c->poll_entry->revents & (POLLERR | POLLHUP))
  517.             return -1;
  518.  
  519.         /* no need to read if no events */
  520.         if (!(c->poll_entry->revents & POLLOUT))
  521.             return 0;
  522.         len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
  523.         if (len < 0) {
  524.             if (errno != EAGAIN && errno != EINTR) {
  525.                 /* error : close connection */
  526.                 return -1;
  527.             }
  528.         } else {
  529.             c->buffer_ptr += len;
  530.             if (c->stream)
  531.                 c->stream->bytes_served += len;
  532.             c->data_count += len;
  533.             if (c->buffer_ptr >= c->buffer_end) {
  534.                 /* if error, exit */
  535.                 if (c->http_error)
  536.                     return -1;
  537.                 /* all the buffer was send : synchronize to the incoming stream */
  538.                 c->state = HTTPSTATE_SEND_DATA_HEADER;
  539.                 c->buffer_ptr = c->buffer_end = c->buffer;
  540.             }
  541.         }
  542.         break;
  543.  
  544.     case HTTPSTATE_SEND_DATA:
  545.     case HTTPSTATE_SEND_DATA_HEADER:
  546.     case HTTPSTATE_SEND_DATA_TRAILER:
  547.         /* no need to read if no events */
  548.         if (c->poll_entry->revents & (POLLERR | POLLHUP))
  549.             return -1;
  550.         
  551.         if (!(c->poll_entry->revents & POLLOUT))
  552.             return 0;
  553.         if (http_send_data(c) < 0)
  554.             return -1;
  555.         break;
  556.     case HTTPSTATE_RECEIVE_DATA:
  557.         /* no need to read if no events */
  558.         if (c->poll_entry->revents & (POLLERR | POLLHUP))
  559.             return -1;
  560.         if (!(c->poll_entry->revents & POLLIN))
  561.             return 0;
  562.         if (http_receive_data(c) < 0)
  563.             return -1;
  564.         break;
  565.     case HTTPSTATE_WAIT_FEED:
  566.         /* no need to read if no events */
  567.         if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
  568.             return -1;
  569.  
  570.         /* nothing to do, we'll be waken up by incoming feed packets */
  571.         break;
  572.     default:
  573.         return -1;
  574.     }
  575.     return 0;
  576. }
  577.  
  578. static int extract_rates(char *rates, int ratelen, const char *request)
  579. {
  580.     const char *p;
  581.  
  582.     for (p = request; *p && *p != '\r' && *p != '\n'; ) {
  583.         if (strncasecmp(p, "Pragma:", 7) == 0) {
  584.             const char *q = p + 7;
  585.  
  586.             while (*q && *q != '\n' && isspace(*q))
  587.                 q++;
  588.  
  589.             if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
  590.                 int stream_no;
  591.                 int rate_no;
  592.  
  593.                 q += 20;
  594.  
  595.                 memset(rates, 0xff, ratelen);
  596.  
  597.                 while (1) {
  598.                     while (*q && *q != '\n' && *q != ':')
  599.                         q++;
  600.  
  601.                     if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2) {
  602.                         break;
  603.                     }
  604.                     stream_no--;
  605.                     if (stream_no < ratelen && stream_no >= 0) {
  606.                         rates[stream_no] = rate_no;
  607.                     }
  608.  
  609.                     while (*q && *q != '\n' && !isspace(*q))
  610.                         q++;
  611.                 }
  612.  
  613.                 return 1;
  614.             }
  615.         }
  616.         p = strchr(p, '\n');
  617.         if (!p)
  618.             break;
  619.  
  620.         p++;
  621.     }
  622.  
  623.     return 0;
  624. }
  625.  
  626. static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
  627. {
  628.     int i;
  629.     int best_bitrate = 100000000;
  630.     int best = -1;
  631.  
  632.     for (i = 0; i < feed->nb_streams; i++) {
  633.         AVCodecContext *feed_codec = &feed->streams[i]->codec;
  634.  
  635.         if (feed_codec->codec_id != codec->codec_id ||
  636.             feed_codec->sample_rate != codec->sample_rate ||
  637.             feed_codec->width != codec->width ||
  638.             feed_codec->height != codec->height) {
  639.             continue;
  640.         }
  641.  
  642.         /* Potential stream */
  643.  
  644.         /* We want the fastest stream less than bit_rate, or the slowest 
  645.          * faster than bit_rate
  646.          */
  647.  
  648.         if (feed_codec->bit_rate <= bit_rate) {
  649.             if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
  650.                 best_bitrate = feed_codec->bit_rate;
  651.                 best = i;
  652.             }
  653.         } else {
  654.             if (feed_codec->bit_rate < best_bitrate) {
  655.                 best_bitrate = feed_codec->bit_rate;
  656.                 best = i;
  657.             }
  658.         }
  659.     }
  660.  
  661.     return best;
  662. }
  663.  
  664. static int modify_current_stream(HTTPContext *c, char *rates)
  665. {
  666.     int i;
  667.     FFStream *req = c->stream;
  668.     int action_required = 0;
  669.  
  670.     for (i = 0; i < req->nb_streams; i++) {
  671.         AVCodecContext *codec = &req->streams[i]->codec;
  672.  
  673.         switch(rates[i]) {
  674.             case 0:
  675.                 c->switch_feed_streams[i] = req->feed_streams[i];
  676.                 break;
  677.             case 1:
  678.                 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
  679.                 break;
  680.             case 2:
  681.                 /* Wants off or slow */
  682.                 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
  683. #ifdef WANTS_OFF
  684.                 /* This doesn't work well when it turns off the only stream! */
  685.                 c->switch_feed_streams[i] = -2;
  686.                 c->feed_streams[i] = -2;
  687. #endif
  688.                 break;
  689.         }
  690.  
  691.         if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
  692.             action_required = 1;
  693.     }
  694.  
  695.     return action_required;
  696. }
  697.  
  698.  
  699. static void do_switch_stream(HTTPContext *c, int i)
  700. {
  701.     if (c->switch_feed_streams[i] >= 0) {
  702. #ifdef PHILIP        
  703.         c->feed_streams[i] = c->switch_feed_streams[i];
  704. #endif
  705.  
  706.         /* Now update the stream */
  707.     }
  708.     c->switch_feed_streams[i] = -1;
  709. }
  710.  
  711. /* parse http request and prepare header */
  712. static int http_parse_request(HTTPContext *c)
  713. {
  714.     char *p;
  715.     int post;
  716.     int doing_asx;
  717.     int doing_asf_redirector;
  718.     int doing_ram;
  719.     char cmd[32];
  720.     char info[1024], *filename;
  721.     char url[1024], *q;
  722.     char protocol[32];
  723.     char msg[1024];
  724.     const char *mime_type;
  725.     FFStream *stream;
  726.     int i;
  727.     char ratebuf[32];
  728.     char *useragent = 0;
  729.  
  730.     p = c->buffer;
  731.     q = cmd;
  732.     while (!isspace(*p) && *p != '\0') {
  733.         if ((q - cmd) < sizeof(cmd) - 1)
  734.             *q++ = *p;
  735.         p++;
  736.     }
  737.     *q = '\0';
  738.  
  739.     pstrcpy(c->method, sizeof(c->method), cmd);
  740.  
  741.     if (!strcmp(cmd, "GET"))
  742.         post = 0;
  743.     else if (!strcmp(cmd, "POST"))
  744.         post = 1;
  745.     else
  746.         return -1;
  747.  
  748.     while (isspace(*p)) p++;
  749.     q = url;
  750.     while (!isspace(*p) && *p != '\0') {
  751.         if ((q - url) < sizeof(url) - 1)
  752.             *q++ = *p;
  753.         p++;
  754.     }
  755.     *q = '\0';
  756.  
  757.     pstrcpy(c->url, sizeof(c->url), url);
  758.  
  759.     while (isspace(*p)) p++;
  760.     q = protocol;
  761.     while (!isspace(*p) && *p != '\0') {
  762.         if ((q - protocol) < sizeof(protocol) - 1)
  763.             *q++ = *p;
  764.         p++;
  765.     }
  766.     *q = '\0';
  767.     if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
  768.         return -1;
  769.  
  770.     pstrcpy(c->protocol, sizeof(c->protocol), protocol);
  771.     
  772.     /* find the filename and the optional info string in the request */
  773.     p = url;
  774.     if (*p == '/')
  775.         p++;
  776.     filename = p;
  777.     p = strchr(p, '?');
  778.     if (p) {
  779.         pstrcpy(info, sizeof(info), p);
  780.         *p = '\0';
  781.     } else {
  782.         info[0] = '\0';
  783.     }
  784.  
  785.     for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
  786.         if (strncasecmp(p, "User-Agent:", 11) == 0) {
  787.             useragent = p + 11;
  788.             if (*useragent && *useragent != '\n' && isspace(*useragent))
  789.                 useragent++;
  790.             break;
  791.         }
  792.         p = strchr(p, '\n');
  793.         if (!p)
  794.             break;
  795.  
  796.         p++;
  797.     }
  798.  
  799.     if (strlen(filename) > 4 && strcmp(".asx", filename + strlen(filename) - 4) == 0) {
  800.         doing_asx = 1;
  801.         filename[strlen(filename)-1] = 'f';
  802.     } else {
  803.         doing_asx = 0;
  804.     }
  805.  
  806.     if (strlen(filename) > 4 && strcmp(".asf", filename + strlen(filename) - 4) == 0 &&
  807.         (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
  808.         /* if this isn't WMP or lookalike, return the redirector file */
  809.         doing_asf_redirector = 1;
  810.     } else {
  811.         doing_asf_redirector = 0;
  812.     }
  813.  
  814.     if (strlen(filename) > 4 && 
  815.         (strcmp(".rpm", filename + strlen(filename) - 4) == 0 ||
  816.          strcmp(".ram", filename + strlen(filename) - 4) == 0)) {
  817.         doing_ram = 1;
  818.         strcpy(filename + strlen(filename)-2, "m");
  819.     } else {
  820.         doing_ram = 0;
  821.     }
  822.  
  823.     stream = first_stream;
  824.     while (stream != NULL) {
  825.         if (!strcmp(stream->filename, filename))
  826.             break;
  827.         stream = stream->next;
  828.     }
  829.     if (stream == NULL) {
  830.         sprintf(msg, "File '%s' not found", url);
  831.         goto send_error;
  832.     }
  833.  
  834.     c->stream = stream;
  835.     memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
  836.     memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
  837.  
  838.     if (stream->stream_type == STREAM_TYPE_REDIRECT) {
  839.         c->http_error = 301;
  840.         q = c->buffer;
  841.         q += sprintf(q, "HTTP/1.0 301 Moved\r\n");
  842.         q += sprintf(q, "Location: %s\r\n", stream->feed_filename);
  843.         q += sprintf(q, "Content-type: text/html\r\n");
  844.         q += sprintf(q, "\r\n");
  845.         q += sprintf(q, "<html><head><title>Moved</title></head><body>\r\n");
  846.         q += sprintf(q, "You should be <a href=\"%s\">redirected</a>.\r\n", stream->feed_filename);
  847.         q += sprintf(q, "</body></html>\r\n");
  848.  
  849.         /* prepare output buffer */
  850.         c->buffer_ptr = c->buffer;
  851.         c->buffer_end = q;
  852.         c->state = HTTPSTATE_SEND_HEADER;
  853.         return 0;
  854.     }
  855.  
  856.     /* If this is WMP, get the rate information */
  857.     if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
  858.         if (modify_current_stream(c, ratebuf)) {
  859.             for (i = 0; i < sizeof(c->feed_streams) / sizeof(c->feed_streams[0]); i++) {
  860.                 if (c->switch_feed_streams[i] >= 0)
  861.                     do_switch_stream(c, i);
  862.             }
  863.         }
  864.     }
  865.  
  866.     if (post == 0 && stream->stream_type == STREAM_TYPE_LIVE) {
  867.         /* See if we meet the bandwidth requirements */
  868.         for(i=0;i<stream->nb_streams;i++) {
  869.             AVStream *st = stream->streams[i];
  870.             switch(st->codec.codec_type) {
  871.             case CODEC_TYPE_AUDIO:
  872.                 c->bandwidth += st->codec.bit_rate;
  873.                 break;
  874.             case CODEC_TYPE_VIDEO:
  875.                 c->bandwidth += st->codec.bit_rate;
  876.                 break;
  877.             default:
  878.                 av_abort();
  879.             }
  880.         }
  881.     }
  882.  
  883.     c->bandwidth /= 1000;
  884.     nb_bandwidth += c->bandwidth;
  885.  
  886.     if (post == 0 && nb_max_bandwidth < nb_bandwidth) {
  887.         c->http_error = 200;
  888.         q = c->buffer;
  889.         q += sprintf(q, "HTTP/1.0 200 Server too busy\r\n");
  890.         q += sprintf(q, "Content-type: text/html\r\n");
  891.         q += sprintf(q, "\r\n");
  892.         q += sprintf(q, "<html><head><title>Too busy</title></head><body>\r\n");
  893.         q += sprintf(q, "The server is too busy to serve your request at this time.<p>\r\n");
  894.         q += sprintf(q, "The bandwidth being served (including your stream) is %dkbit/sec, and this exceeds the limit of %dkbit/sec\r\n",
  895.             nb_bandwidth, nb_max_bandwidth);
  896.         q += sprintf(q, "</body></html>\r\n");
  897.  
  898.         /* prepare output buffer */
  899.         c->buffer_ptr = c->buffer;
  900.         c->buffer_end = q;
  901.         c->state = HTTPSTATE_SEND_HEADER;
  902.         return 0;
  903.     }
  904.     
  905.     if (doing_asx || doing_ram || doing_asf_redirector) {
  906.         char *hostinfo = 0;
  907.         
  908.         for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
  909.             if (strncasecmp(p, "Host:", 5) == 0) {
  910.                 hostinfo = p + 5;
  911.                 break;
  912.             }
  913.             p = strchr(p, '\n');
  914.             if (!p)
  915.                 break;
  916.  
  917.             p++;
  918.         }
  919.  
  920.         if (hostinfo) {
  921.             char *eoh;
  922.             char hostbuf[260];
  923.  
  924.             while (isspace(*hostinfo))
  925.                 hostinfo++;
  926.  
  927.             eoh = strchr(hostinfo, '\n');
  928.             if (eoh) {
  929.                 if (eoh[-1] == '\r')
  930.                     eoh--;
  931.  
  932.                 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
  933.                     memcpy(hostbuf, hostinfo, eoh - hostinfo);
  934.                     hostbuf[eoh - hostinfo] = 0;
  935.  
  936.                     c->http_error = 200;
  937.                     q = c->buffer;
  938.                     if (doing_asx) {
  939.                         q += sprintf(q, "HTTP/1.0 200 ASX Follows\r\n");
  940.                         q += sprintf(q, "Content-type: video/x-ms-asf\r\n");
  941.                         q += sprintf(q, "\r\n");
  942.                         q += sprintf(q, "<ASX Version=\"3\">\r\n");
  943.                         q += sprintf(q, "<!-- Autogenerated by ffserver -->\r\n");
  944.                         q += sprintf(q, "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n", 
  945.                                 hostbuf, filename, info);
  946.                         q += sprintf(q, "</ASX>\r\n");
  947.                     } else if (doing_ram) {
  948.                         q += sprintf(q, "HTTP/1.0 200 RAM Follows\r\n");
  949.                         q += sprintf(q, "Content-type: audio/x-pn-realaudio\r\n");
  950.                         q += sprintf(q, "\r\n");
  951.                         q += sprintf(q, "# Autogenerated by ffserver\r\n");
  952.                         q += sprintf(q, "http://%s/%s%s\r\n", 
  953.                                 hostbuf, filename, info);
  954.                     } else if (doing_asf_redirector) {
  955.                         q += sprintf(q, "HTTP/1.0 200 ASF Redirect follows\r\n");
  956.                         q += sprintf(q, "Content-type: video/x-ms-asf\r\n");
  957.                         q += sprintf(q, "\r\n");
  958.                         q += sprintf(q, "[Reference]\r\n");
  959.                         q += sprintf(q, "Ref1=http://%s/%s%s\r\n", 
  960.                                 hostbuf, filename, info);
  961.                     } else
  962.                         av_abort();
  963.  
  964.                     /* prepare output buffer */
  965.                     c->buffer_ptr = c->buffer;
  966.                     c->buffer_end = q;
  967.                     c->state = HTTPSTATE_SEND_HEADER;
  968.                     return 0;
  969.                 }
  970.             }
  971.         }
  972.  
  973.         sprintf(msg, "ASX/RAM file not handled");
  974.         goto send_error;
  975.     }
  976.  
  977.     stream->conns_served++;
  978.  
  979.     /* XXX: add there authenticate and IP match */
  980.  
  981.     if (post) {
  982.         /* if post, it means a feed is being sent */
  983.         if (!stream->is_feed) {
  984.             /* However it might be a status report from WMP! Lets log the data
  985.              * as it might come in handy one day
  986.              */
  987.             char *logline = 0;
  988.             int client_id = 0;
  989.             
  990.             for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
  991.                 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
  992.                     logline = p;
  993.                     break;
  994.                 }
  995.                 if (strncasecmp(p, "Pragma: client-id=", 18) == 0) {
  996.                     client_id = strtol(p + 18, 0, 10);
  997.                 }
  998.                 p = strchr(p, '\n');
  999.                 if (!p)
  1000.                     break;
  1001.  
  1002.                 p++;
  1003.             }
  1004.  
  1005.             if (logline) {
  1006.                 char *eol = strchr(logline, '\n');
  1007.  
  1008.                 logline += 17;
  1009.  
  1010.                 if (eol) {
  1011.                     if (eol[-1] == '\r')
  1012.                         eol--;
  1013.                     http_log("%.*s\n", eol - logline, logline);
  1014.                     c->suppress_log = 1;
  1015.                 }
  1016.             }
  1017.  
  1018. #ifdef DEBUG_WMP
  1019.             http_log("\nGot request:\n%s\n", c->buffer);
  1020. #endif
  1021.  
  1022.             if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
  1023.                 HTTPContext *wmpc;
  1024.  
  1025.                 /* Now we have to find the client_id */
  1026.                 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
  1027.                     if (wmpc->wmp_client_id == client_id)
  1028.                         break;
  1029.                 }
  1030.  
  1031.                 if (wmpc) {
  1032.                     if (modify_current_stream(wmpc, ratebuf)) {
  1033.                         wmpc->switch_pending = 1;
  1034.                     }
  1035.                 }
  1036.             }
  1037.             
  1038.             sprintf(msg, "POST command not handled");
  1039.             goto send_error;
  1040.         }
  1041.         if (http_start_receive_data(c) < 0) {
  1042.             sprintf(msg, "could not open feed");
  1043.             goto send_error;
  1044.         }
  1045.         c->http_error = 0;
  1046.         c->state = HTTPSTATE_RECEIVE_DATA;
  1047.         return 0;
  1048.     }
  1049.  
  1050. #ifdef DEBUG_WMP
  1051.     if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0) {
  1052.         http_log("\nGot request:\n%s\n", c->buffer);
  1053.     }
  1054. #endif
  1055.  
  1056.     if (c->stream->stream_type == STREAM_TYPE_STATUS)
  1057.         goto send_stats;
  1058.  
  1059.     /* open input stream */
  1060.     if (open_input_stream(c, info) < 0) {
  1061.         sprintf(msg, "Input stream corresponding to '%s' not found", url);
  1062.         goto send_error;
  1063.     }
  1064.  
  1065.     /* prepare http header */
  1066.     q = c->buffer;
  1067.     q += sprintf(q, "HTTP/1.0 200 OK\r\n");
  1068.     mime_type = c->stream->fmt->mime_type;
  1069.     if (!mime_type)
  1070.         mime_type = "application/x-octet_stream";
  1071.     q += sprintf(q, "Pragma: no-cache\r\n");
  1072.  
  1073.     /* for asf, we need extra headers */
  1074.     if (!strcmp(c->stream->fmt->name,"asf")) {
  1075.         /* Need to allocate a client id */
  1076.         static int wmp_session;
  1077.  
  1078.         if (!wmp_session)
  1079.             wmp_session = time(0) & 0xffffff;
  1080.  
  1081.         c->wmp_client_id = ++wmp_session;
  1082.  
  1083.         q += sprintf(q, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id);
  1084.         mime_type = "application/octet-stream"; 
  1085.     }
  1086.     q += sprintf(q, "Content-Type: %s\r\n", mime_type);
  1087.     q += sprintf(q, "\r\n");
  1088.     
  1089.     /* prepare output buffer */
  1090.     c->http_error = 0;
  1091.     c->buffer_ptr = c->buffer;
  1092.     c->buffer_end = q;
  1093.     c->state = HTTPSTATE_SEND_HEADER;
  1094.     return 0;
  1095.  send_error:
  1096.     c->http_error = 404;
  1097.     q = c->buffer;
  1098.     q += sprintf(q, "HTTP/1.0 404 Not Found\r\n");
  1099.     q += sprintf(q, "Content-type: %s\r\n", "text/html");
  1100.     q += sprintf(q, "\r\n");
  1101.     q += sprintf(q, "<HTML>\n");
  1102.     q += sprintf(q, "<HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
  1103.     q += sprintf(q, "<BODY>%s</BODY>\n", msg);
  1104.     q += sprintf(q, "</HTML>\n");
  1105.  
  1106.     /* prepare output buffer */
  1107.     c->buffer_ptr = c->buffer;
  1108.     c->buffer_end = q;
  1109.     c->state = HTTPSTATE_SEND_HEADER;
  1110.     return 0;
  1111.  send_stats:
  1112.     compute_stats(c);
  1113.     c->http_error = 200; /* horrible : we use this value to avoid
  1114.                             going to the send data state */
  1115.     c->state = HTTPSTATE_SEND_HEADER;
  1116.     return 0;
  1117. }
  1118.  
  1119. static int fmt_bytecount(char *q, INT64 count)
  1120. {
  1121.     static const char *suffix = " kMGTP";
  1122.     const char *s;
  1123.  
  1124.     for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++) {
  1125.     }
  1126.  
  1127.     return sprintf(q, "%lld%c", count, *s);
  1128. }
  1129.  
  1130. static void compute_stats(HTTPContext *c)
  1131. {
  1132.     HTTPContext *c1;
  1133.     FFStream *stream;
  1134.     char *q, *p;
  1135.     time_t ti;
  1136.     int i;
  1137.     char *new_buffer;
  1138.  
  1139.     new_buffer = av_malloc(65536);
  1140.     if (new_buffer) {
  1141.         av_free(c->buffer);
  1142.         c->buffer_size = 65536;
  1143.         c->buffer = new_buffer;
  1144.         c->buffer_ptr = c->buffer;
  1145.         c->buffer_end = c->buffer + c->buffer_size;
  1146.     }
  1147.  
  1148.     q = c->buffer;
  1149.     q += sprintf(q, "HTTP/1.0 200 OK\r\n");
  1150.     q += sprintf(q, "Content-type: %s\r\n", "text/html");
  1151.     q += sprintf(q, "Pragma: no-cache\r\n");
  1152.     q += sprintf(q, "\r\n");
  1153.     
  1154.     q += sprintf(q, "<HEAD><TITLE>FFServer Status</TITLE>\n");
  1155.     if (c->stream->feed_filename) {
  1156.         q += sprintf(q, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
  1157.     }
  1158.     q += sprintf(q, "</HEAD>\n<BODY>");
  1159.     q += sprintf(q, "<H1>FFServer Status</H1>\n");
  1160.     /* format status */
  1161.     q += sprintf(q, "<H2>Available Streams</H2>\n");
  1162.     q += sprintf(q, "<TABLE cellspacing=0 cellpadding=4>\n");
  1163.     q += sprintf(q, "<TR><Th valign=top>Path<th align=left>Served<br>Conns<Th><br>bytes<Th valign=top>Format<Th>Bit rate<br>kbits/s<Th align=left>Video<br>kbits/s<th><br>Codec<Th align=left>Audio<br>kbits/s<th><br>Codec<Th align=left valign=top>Feed\n");
  1164.     stream = first_stream;
  1165.     while (stream != NULL) {
  1166.         char sfilename[1024];
  1167.         char *eosf;
  1168.  
  1169.         if (stream->feed != stream) {
  1170.             pstrcpy(sfilename, sizeof(sfilename) - 1, stream->filename);
  1171.             eosf = sfilename + strlen(sfilename);
  1172.             if (eosf - sfilename >= 4) {
  1173.                 if (strcmp(eosf - 4, ".asf") == 0) {
  1174.                     strcpy(eosf - 4, ".asx");
  1175.                 } else if (strcmp(eosf - 3, ".rm") == 0) {
  1176.                     strcpy(eosf - 3, ".ram");
  1177.                 }
  1178.             }
  1179.             
  1180.             q += sprintf(q, "<TR><TD><A HREF=\"/%s\">%s</A> ", 
  1181.                          sfilename, stream->filename);
  1182.             q += sprintf(q, "<td align=right> %d <td align=right> ",
  1183.                         stream->conns_served);
  1184.             q += fmt_bytecount(q, stream->bytes_served);
  1185.             switch(stream->stream_type) {
  1186.             case STREAM_TYPE_LIVE:
  1187.                 {
  1188.                     int audio_bit_rate = 0;
  1189.                     int video_bit_rate = 0;
  1190.                     char *audio_codec_name = "";
  1191.                     char *video_codec_name = "";
  1192.                     char *audio_codec_name_extra = "";
  1193.                     char *video_codec_name_extra = "";
  1194.  
  1195.                     for(i=0;i<stream->nb_streams;i++) {
  1196.                         AVStream *st = stream->streams[i];
  1197.                         AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
  1198.                         switch(st->codec.codec_type) {
  1199.                         case CODEC_TYPE_AUDIO:
  1200.                             audio_bit_rate += st->codec.bit_rate;
  1201.                             if (codec) {
  1202.                                 if (*audio_codec_name)
  1203.                                     audio_codec_name_extra = "...";
  1204.                                 audio_codec_name = codec->name;
  1205.                             }
  1206.                             break;
  1207.                         case CODEC_TYPE_VIDEO:
  1208.                             video_bit_rate += st->codec.bit_rate;
  1209.                             if (codec) {
  1210.                                 if (*video_codec_name)
  1211.                                     video_codec_name_extra = "...";
  1212.                                 video_codec_name = codec->name;
  1213.                             }
  1214.                             break;
  1215.                         default:
  1216.                             av_abort();
  1217.                         }
  1218.                     }
  1219.                     q += sprintf(q, "<TD align=center> %s <TD align=right> %d <TD align=right> %d <TD> %s %s <TD align=right> %d <TD> %s %s", 
  1220.                                  stream->fmt->name,
  1221.                                  (audio_bit_rate + video_bit_rate) / 1000,
  1222.                                  video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
  1223.                                  audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
  1224.                     if (stream->feed) {
  1225.                         q += sprintf(q, "<TD>%s", stream->feed->filename);
  1226.                     } else {
  1227.                         q += sprintf(q, "<TD>%s", stream->feed_filename);
  1228.                     }
  1229.                     q += sprintf(q, "\n");
  1230.                 }
  1231.                 break;
  1232.             default:
  1233.                 q += sprintf(q, "<TD align=center> - <TD align=right> - <TD align=right> - <td><td align=right> - <TD>\n");
  1234.                 break;
  1235.             }
  1236.         }
  1237.         stream = stream->next;
  1238.     }
  1239.     q += sprintf(q, "</TABLE>\n");
  1240.  
  1241.     stream = first_stream;
  1242.     while (stream != NULL) {
  1243.         if (stream->feed == stream) {
  1244.             q += sprintf(q, "<h2>Feed %s</h2>", stream->filename);
  1245.             if (stream->pid) {
  1246.                 FILE *pid_stat;
  1247.                 char ps_cmd[64];
  1248.  
  1249.                 q += sprintf(q, "Running as pid %d.\n", stream->pid);
  1250.  
  1251. #ifdef linux
  1252.                 /* This is somewhat linux specific I guess */
  1253.                 snprintf(ps_cmd, sizeof(ps_cmd), "ps -o \"%%cpu,bsdtime\" --no-headers %d", stream->pid);
  1254.  
  1255.                 pid_stat = popen(ps_cmd, "r");
  1256.                 if (pid_stat) {
  1257.                     char cpuperc[10];
  1258.                     char cpuused[64];
  1259.  
  1260.                     if (fscanf(pid_stat, "%10s %64s", cpuperc, cpuused) == 2) {
  1261.                         q += sprintf(q, "Currently using %s%% of the cpu. Total time used %s.\n",
  1262.                             cpuperc, cpuused);
  1263.                     }
  1264.                     fclose(pid_stat);
  1265.                 }
  1266. #endif
  1267.  
  1268.                 q += sprintf(q, "<p>");
  1269.             }
  1270.             q += sprintf(q, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
  1271.  
  1272.             for (i = 0; i < stream->nb_streams; i++) {
  1273.                 AVStream *st = stream->streams[i];
  1274.                 AVCodec *codec = avcodec_find_encoder(st->codec.codec_id);
  1275.                 char *type = "unknown";
  1276.                 char parameters[64];
  1277.  
  1278.                 parameters[0] = 0;
  1279.  
  1280.                 switch(st->codec.codec_type) {
  1281.                 case CODEC_TYPE_AUDIO:
  1282.                     type = "audio";
  1283.                     break;
  1284.                 case CODEC_TYPE_VIDEO:
  1285.                     type = "video";
  1286.                     sprintf(parameters, "%dx%d, q=%d-%d, fps=%d", st->codec.width, st->codec.height,
  1287.                                 st->codec.qmin, st->codec.qmax, st->codec.frame_rate / FRAME_RATE_BASE);
  1288.                     break;
  1289.                 default:
  1290.                     av_abort();
  1291.                 }
  1292.                 q += sprintf(q, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
  1293.                         i, type, st->codec.bit_rate/1000, codec ? codec->name : "", parameters);
  1294.             }
  1295.             q += sprintf(q, "</table>\n");
  1296.  
  1297.         }       
  1298.         stream = stream->next;
  1299.     }
  1300.     
  1301. #if 0
  1302.     {
  1303.         float avg;
  1304.         AVCodecContext *enc;
  1305.         char buf[1024];
  1306.         
  1307.         /* feed status */
  1308.         stream = first_feed;
  1309.         while (stream != NULL) {
  1310.             q += sprintf(q, "<H1>Feed '%s'</H1>\n", stream->filename);
  1311.             q += sprintf(q, "<TABLE>\n");
  1312.             q += sprintf(q, "<TR><TD>Parameters<TD>Frame count<TD>Size<TD>Avg bitrate (kbits/s)\n");
  1313.             for(i=0;i<stream->nb_streams;i++) {
  1314.                 AVStream *st = stream->streams[i];
  1315.                 FeedData *fdata = st->priv_data;
  1316.                 enc = &st->codec;
  1317.             
  1318.                 avcodec_string(buf, sizeof(buf), enc);
  1319.                 avg = fdata->avg_frame_size * (float)enc->rate * 8.0;
  1320.                 if (enc->codec->type == CODEC_TYPE_AUDIO && enc->frame_size > 0)
  1321.                     avg /= enc->frame_size;
  1322.                 q += sprintf(q, "<TR><TD>%s <TD> %d <TD> %Ld <TD> %0.1f\n", 
  1323.                              buf, enc->frame_number, fdata->data_count, avg / 1000.0);
  1324.             }
  1325.             q += sprintf(q, "</TABLE>\n");
  1326.             stream = stream->next_feed;
  1327.         }
  1328.     }
  1329. #endif
  1330.  
  1331.     /* connection status */
  1332.     q += sprintf(q, "<H2>Connection Status</H2>\n");
  1333.  
  1334.     q += sprintf(q, "Number of connections: %d / %d<BR>\n",
  1335.                  nb_connections, nb_max_connections);
  1336.  
  1337.     q += sprintf(q, "Bandwidth in use: %dk / %dk<BR>\n",
  1338.                  nb_bandwidth, nb_max_bandwidth);
  1339.  
  1340.     q += sprintf(q, "<TABLE>\n");
  1341.     q += sprintf(q, "<TR><Th>#<Th>File<Th>IP<Th>State<Th>Target bits/sec<Th>Actual bits/sec<Th>Bytes transferred\n");
  1342.     c1 = first_http_ctx;
  1343.     i = 0;
  1344.     while (c1 != NULL && q < (char *) c->buffer + c->buffer_size - 2048) {
  1345.         int bitrate;
  1346.         int j;
  1347.  
  1348.         bitrate = 0;
  1349.         for (j = 0; j < c1->stream->nb_streams; j++) {
  1350.             if (c1->feed_streams[j] >= 0) {
  1351.                 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec.bit_rate;
  1352.             }
  1353.         }
  1354.  
  1355.         i++;
  1356.         p = inet_ntoa(c1->from_addr.sin_addr);
  1357.         q += sprintf(q, "<TR><TD><B>%d</B><TD>%s%s <TD> %s <TD> %s <td align=right>", 
  1358.                      i, c1->stream->filename, 
  1359.                      c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
  1360.                      p, 
  1361.                      http_state[c1->state]);
  1362.         q += fmt_bytecount(q, bitrate);
  1363.         q += sprintf(q, "<td align=right>");
  1364.         q += fmt_bytecount(q, compute_datarate(&c1->datarate, c1->data_count) * 8);
  1365.         q += sprintf(q, "<td align=right>");
  1366.         q += fmt_bytecount(q, c1->data_count);
  1367.         *q++ = '\n';
  1368.         c1 = c1->next;
  1369.     }
  1370.     q += sprintf(q, "</TABLE>\n");
  1371.     
  1372.     /* date */
  1373.     ti = time(NULL);
  1374.     p = ctime(&ti);
  1375.     q += sprintf(q, "<HR size=1 noshade>Generated at %s", p);
  1376.     q += sprintf(q, "</BODY>\n</HTML>\n");
  1377.  
  1378.     c->buffer_ptr = c->buffer;
  1379.     c->buffer_end = q;
  1380. }
  1381.  
  1382.  
  1383. static void http_write_packet(void *opaque, 
  1384.                               unsigned char *buf, int size)
  1385. {
  1386.     HTTPContext *c = opaque;
  1387.  
  1388.     if (c->buffer_ptr == c->buffer_end || !c->buffer_ptr)
  1389.         c->buffer_ptr = c->buffer_end = c->buffer;
  1390.  
  1391.     if (c->buffer_end - c->buffer + size > c->buffer_size) {
  1392.         int new_buffer_size = c->buffer_size * 2;
  1393.         UINT8 *new_buffer;
  1394.  
  1395.         if (new_buffer_size <= c->buffer_end - c->buffer + size) {
  1396.             new_buffer_size = c->buffer_end - c->buffer + size + c->buffer_size;
  1397.         }
  1398.  
  1399.         new_buffer = av_malloc(new_buffer_size);
  1400.         if (new_buffer) {
  1401.             memcpy(new_buffer, c->buffer, c->buffer_end - c->buffer);
  1402.             c->buffer_end += (new_buffer - c->buffer);
  1403.             c->buffer_ptr += (new_buffer - c->buffer);
  1404.             av_free(c->buffer);
  1405.             c->buffer = new_buffer;
  1406.             c->buffer_size = new_buffer_size;
  1407.         } else {
  1408.             av_abort();
  1409.         }
  1410.     }
  1411.  
  1412.     memcpy(c->buffer_end, buf, size);
  1413.     c->buffer_end += size;
  1414. }
  1415.  
  1416. static int open_input_stream(HTTPContext *c, const char *info)
  1417. {
  1418.     char buf[128];
  1419.     char input_filename[1024];
  1420.     AVFormatContext *s;
  1421.     int buf_size;
  1422.     INT64 stream_pos;
  1423.  
  1424.     /* find file name */
  1425.     if (c->stream->feed) {
  1426.         strcpy(input_filename, c->stream->feed->feed_filename);
  1427.         buf_size = FFM_PACKET_SIZE;
  1428.         /* compute position (absolute time) */
  1429.         if (find_info_tag(buf, sizeof(buf), "date", info)) {
  1430.             stream_pos = parse_date(buf, 0);
  1431.         } else if (find_info_tag(buf, sizeof(buf), "buffer", info)) {
  1432.             int prebuffer = strtol(buf, 0, 10);
  1433.             stream_pos = gettime() - prebuffer * 1000000;
  1434.         } else {
  1435.             stream_pos = gettime() - c->stream->prebuffer * 1000;
  1436.         }
  1437.     } else {
  1438.         strcpy(input_filename, c->stream->feed_filename);
  1439.         buf_size = 0;
  1440.         /* compute position (relative time) */
  1441.         if (find_info_tag(buf, sizeof(buf), "date", info)) {
  1442.             stream_pos = parse_date(buf, 1);
  1443.         } else {
  1444.             stream_pos = 0;
  1445.         }
  1446.     }
  1447.     if (input_filename[0] == '\0')
  1448.         return -1;
  1449.  
  1450.     /* open stream */
  1451.     if (av_open_input_file(&s, input_filename, NULL, buf_size, NULL) < 0)
  1452.         return -1;
  1453.     c->fmt_in = s;
  1454.  
  1455.     if (c->fmt_in->iformat->read_seek) {
  1456.         c->fmt_in->iformat->read_seek(c->fmt_in, stream_pos);
  1457.     }
  1458.     
  1459.     //    printf("stream %s opened pos=%0.6f\n", input_filename, stream_pos / 1000000.0);
  1460.     return 0;
  1461. }
  1462.  
  1463. static int http_prepare_data(HTTPContext *c)
  1464. {
  1465.     int i;
  1466.  
  1467.     switch(c->state) {
  1468.     case HTTPSTATE_SEND_DATA_HEADER:
  1469.         memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
  1470.         pstrcpy(c->fmt_ctx.author, sizeof(c->fmt_ctx.author), c->stream->author);
  1471.         pstrcpy(c->fmt_ctx.comment, sizeof(c->fmt_ctx.comment), c->stream->comment);
  1472.         pstrcpy(c->fmt_ctx.copyright, sizeof(c->fmt_ctx.copyright), c->stream->copyright);
  1473.         pstrcpy(c->fmt_ctx.title, sizeof(c->fmt_ctx.title), c->stream->title);
  1474.  
  1475.         if (c->stream->feed) {
  1476.             /* open output stream by using specified codecs */
  1477.             c->fmt_ctx.oformat = c->stream->fmt;
  1478.             c->fmt_ctx.nb_streams = c->stream->nb_streams;
  1479.             for(i=0;i<c->fmt_ctx.nb_streams;i++) {
  1480.                 AVStream *st;
  1481.                 st = av_mallocz(sizeof(AVStream));
  1482.                 c->fmt_ctx.streams[i] = st;
  1483.                 if (c->stream->feed == c->stream)
  1484.                     memcpy(st, c->stream->streams[i], sizeof(AVStream));
  1485.                 else
  1486.                     memcpy(st, c->stream->feed->streams[c->stream->feed_streams[i]], sizeof(AVStream));
  1487.  
  1488.                 st->codec.frame_number = 0; /* XXX: should be done in
  1489.                                                AVStream, not in codec */
  1490.             }
  1491.             c->got_key_frame = 0;
  1492.         } else {
  1493.             /* open output stream by using codecs in specified file */
  1494.             c->fmt_ctx.oformat = c->stream->fmt;
  1495.             c->fmt_ctx.nb_streams = c->fmt_in->nb_streams;
  1496.             for(i=0;i<c->fmt_ctx.nb_streams;i++) {
  1497.                 AVStream *st;
  1498.                 st = av_mallocz(sizeof(AVStream));
  1499.                 c->fmt_ctx.streams[i] = st;
  1500.                 memcpy(st, c->fmt_in->streams[i], sizeof(AVStream));
  1501.                 st->codec.frame_number = 0; /* XXX: should be done in
  1502.                                                AVStream, not in codec */
  1503.             }
  1504.             c->got_key_frame = 0;
  1505.         }
  1506.         init_put_byte(&c->fmt_ctx.pb, c->pbuffer, c->pbuffer_size,
  1507.                       1, c, NULL, http_write_packet, NULL);
  1508.         c->fmt_ctx.pb.is_streamed = 1;
  1509.         /* prepare header */
  1510.         av_write_header(&c->fmt_ctx);
  1511.         c->state = HTTPSTATE_SEND_DATA;
  1512.         c->last_packet_sent = 0;
  1513.         break;
  1514.     case HTTPSTATE_SEND_DATA:
  1515.         /* find a new packet */
  1516. #if 0
  1517.         fifo_total_size = http_fifo_write_count - c->last_http_fifo_write_count;
  1518.         if (fifo_total_size >= ((3 * FIFO_MAX_SIZE) / 4)) {
  1519.             /* overflow : resync. We suppose that wptr is at this
  1520.                point a pointer to a valid packet */
  1521.             c->rptr = http_fifo.wptr;
  1522.             c->got_key_frame = 0;
  1523.         }
  1524.         
  1525.         start_rptr = c->rptr;
  1526.         if (fifo_read(&http_fifo, (UINT8 *)&hdr, sizeof(hdr), &c->rptr) < 0)
  1527.             return 0;
  1528.         payload_size = ntohs(hdr.payload_size);
  1529.         payload = av_malloc(payload_size);
  1530.         if (fifo_read(&http_fifo, payload, payload_size, &c->rptr) < 0) {
  1531.             /* cannot read all the payload */
  1532.             av_free(payload);
  1533.             c->rptr = start_rptr;
  1534.             return 0;
  1535.         }
  1536.         
  1537.         c->last_http_fifo_write_count = http_fifo_write_count - 
  1538.             fifo_size(&http_fifo, c->rptr);
  1539.         
  1540.         if (c->stream->stream_type != STREAM_TYPE_MASTER) {
  1541.             /* test if the packet can be handled by this format */
  1542.             ret = 0;
  1543.             for(i=0;i<c->fmt_ctx.nb_streams;i++) {
  1544.                 AVStream *st = c->fmt_ctx.streams[i];
  1545.                 if (test_header(&hdr, &st->codec)) {
  1546.                     /* only begin sending when got a key frame */
  1547.                     if (st->codec.key_frame)
  1548.                         c->got_key_frame |= 1 << i;
  1549.                     if (c->got_key_frame & (1 << i)) {
  1550.                         ret = c->fmt_ctx.format->write_packet(&c->fmt_ctx, i,
  1551.                                                                    payload, payload_size);
  1552.                     }
  1553.                     break;
  1554.                 }
  1555.             }
  1556.             if (ret) {
  1557.                 /* must send trailer now */
  1558.                 c->state = HTTPSTATE_SEND_DATA_TRAILER;
  1559.             }
  1560.         } else {
  1561.             /* master case : send everything */
  1562.             char *q;
  1563.             q = c->buffer;
  1564.             memcpy(q, &hdr, sizeof(hdr));
  1565.             q += sizeof(hdr);
  1566.             memcpy(q, payload, payload_size);
  1567.             q += payload_size;
  1568.             c->buffer_ptr = c->buffer;
  1569.             c->buffer_end = q;
  1570.         }
  1571.         av_free(payload);
  1572. #endif
  1573.         {
  1574.             AVPacket pkt;
  1575.  
  1576.             /* read a packet from the input stream */
  1577.             if (c->stream->feed) {
  1578.                 ffm_set_write_index(c->fmt_in, 
  1579.                                     c->stream->feed->feed_write_index,
  1580.                                     c->stream->feed->feed_size);
  1581.             }
  1582.  
  1583.             if (c->stream->max_time && 
  1584.                 c->stream->max_time + c->start_time - cur_time < 0) {
  1585.                 /* We have timed out */
  1586.                 c->state = HTTPSTATE_SEND_DATA_TRAILER;
  1587.             } else if (av_read_packet(c->fmt_in, &pkt) < 0) {
  1588.                 if (c->stream->feed && c->stream->feed->feed_opened) {
  1589.                     /* if coming from feed, it means we reached the end of the
  1590.                        ffm file, so must wait for more data */
  1591.                     c->state = HTTPSTATE_WAIT_FEED;
  1592.                     return 1; /* state changed */
  1593.                 } else {
  1594.                     /* must send trailer now because eof or error */
  1595.                     c->state = HTTPSTATE_SEND_DATA_TRAILER;
  1596.                 }
  1597.             } else {
  1598.                 /* send it to the appropriate stream */
  1599.                 if (c->stream->feed) {
  1600.                     /* if coming from a feed, select the right stream */
  1601.                     if (c->switch_pending) {
  1602.                         c->switch_pending = 0;
  1603.                         for(i=0;i<c->stream->nb_streams;i++) {
  1604.                             if (c->switch_feed_streams[i] == pkt.stream_index) {
  1605.                                 if (pkt.flags & PKT_FLAG_KEY) {
  1606.                                     do_switch_stream(c, i);
  1607.                                 }
  1608.                             }
  1609.                             if (c->switch_feed_streams[i] >= 0) {
  1610.                                 c->switch_pending = 1;
  1611.                             }
  1612.                         }
  1613.                     }
  1614.                     for(i=0;i<c->stream->nb_streams;i++) {
  1615.                         if (c->feed_streams[i] == pkt.stream_index) {
  1616.                             pkt.stream_index = i;
  1617.                             if (pkt.flags & PKT_FLAG_KEY) {
  1618.                                 c->got_key_frame |= 1 << i;
  1619.                             }
  1620.                             /* See if we have all the key frames, then 
  1621.                              * we start to send. This logic is not quite
  1622.                              * right, but it works for the case of a 
  1623.                              * single video stream with one or more
  1624.                              * audio streams (for which every frame is 
  1625.                              * typically a key frame). 
  1626.                              */
  1627.                             if (!c->stream->send_on_key || ((c->got_key_frame + 1) >> c->stream->nb_streams)) {
  1628.                                 goto send_it;
  1629.                             }
  1630.                         }
  1631.                     }
  1632.                 } else {
  1633.                     AVCodecContext *codec;
  1634.                 send_it:
  1635.                     /* Fudge here */
  1636.                     codec = &c->fmt_ctx.streams[pkt.stream_index]->codec;
  1637.  
  1638.                     codec->key_frame = ((pkt.flags & PKT_FLAG_KEY) != 0);
  1639.  
  1640. #ifdef PJSG
  1641.                     if (codec->codec_type == CODEC_TYPE_AUDIO) {
  1642.                         codec->frame_size = (codec->sample_rate * pkt.duration + 500000) / 1000000;
  1643.                         /* printf("Calculated size %d, from sr %d, duration %d\n", codec->frame_size, codec->sample_rate, pkt.duration); */
  1644.                     }
  1645. #endif
  1646.  
  1647.                     if (av_write_packet(&c->fmt_ctx, &pkt, 0))
  1648.                         c->state = HTTPSTATE_SEND_DATA_TRAILER;
  1649.  
  1650.                     codec->frame_number++;
  1651.                 }
  1652.  
  1653.                 av_free_packet(&pkt);
  1654.             }
  1655.         }
  1656.         break;
  1657.     default:
  1658.     case HTTPSTATE_SEND_DATA_TRAILER:
  1659.         /* last packet test ? */
  1660.         if (c->last_packet_sent)
  1661.             return -1;
  1662.         /* prepare header */
  1663.         av_write_trailer(&c->fmt_ctx);
  1664.         c->last_packet_sent = 1;
  1665.         break;
  1666.     }
  1667.     return 0;
  1668. }
  1669.  
  1670. /* should convert the format at the same time */
  1671. static int http_send_data(HTTPContext *c)
  1672. {
  1673.     int len, ret;
  1674.  
  1675.     while (c->buffer_ptr >= c->buffer_end) {
  1676.         ret = http_prepare_data(c);
  1677.         if (ret < 0)
  1678.             return -1;
  1679.         else if (ret == 0) {
  1680.             continue;
  1681.         } else {
  1682.             /* state change requested */
  1683.             return 0;
  1684.         }
  1685.     }
  1686.  
  1687.     if (c->buffer_end > c->buffer_ptr) {
  1688.         len = write(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
  1689.         if (len < 0) {
  1690.             if (errno != EAGAIN && errno != EINTR) {
  1691.                 /* error : close connection */
  1692.                 return -1;
  1693.             }
  1694.         } else {
  1695.             c->buffer_ptr += len;
  1696.             c->data_count += len;
  1697.             update_datarate(&c->datarate, c->data_count);
  1698.             if (c->stream)
  1699.                 c->stream->bytes_served += len;
  1700.         }
  1701.     }
  1702.     return 0;
  1703. }
  1704.  
  1705. static int http_start_receive_data(HTTPContext *c)
  1706. {
  1707.     int fd;
  1708.  
  1709.     if (c->stream->feed_opened)
  1710.         return -1;
  1711.  
  1712.     /* open feed */
  1713.     fd = open(c->stream->feed_filename, O_RDWR);
  1714.     if (fd < 0)
  1715.         return -1;
  1716.     c->feed_fd = fd;
  1717.     
  1718.     c->stream->feed_write_index = ffm_read_write_index(fd);
  1719.     c->stream->feed_size = lseek(fd, 0, SEEK_END);
  1720.     lseek(fd, 0, SEEK_SET);
  1721.  
  1722.     /* init buffer input */
  1723.     c->buffer_ptr = c->buffer;
  1724.     c->buffer_end = c->buffer + FFM_PACKET_SIZE;
  1725.     c->stream->feed_opened = 1;
  1726.     return 0;
  1727. }
  1728.     
  1729. static int http_receive_data(HTTPContext *c)
  1730. {
  1731.     HTTPContext *c1;
  1732.  
  1733.     if (c->buffer_end > c->buffer_ptr) {
  1734.         int len;
  1735.  
  1736.         len = read(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr);
  1737.         if (len < 0) {
  1738.             if (errno != EAGAIN && errno != EINTR) {
  1739.                 /* error : close connection */
  1740.                 goto fail;
  1741.             }
  1742.         } else if (len == 0) {
  1743.             /* end of connection : close it */
  1744.             goto fail;
  1745.         } else {
  1746.             c->buffer_ptr += len;
  1747.             c->data_count += len;
  1748.             update_datarate(&c->datarate, c->data_count);
  1749.         }
  1750.     }
  1751.  
  1752.     if (c->buffer_ptr >= c->buffer_end) {
  1753.         FFStream *feed = c->stream;
  1754.         /* a packet has been received : write it in the store, except
  1755.            if header */
  1756.         if (c->data_count > FFM_PACKET_SIZE) {
  1757.             
  1758.             //            printf("writing pos=0x%Lx size=0x%Lx\n", feed->feed_write_index, feed->feed_size);
  1759.             /* XXX: use llseek or url_seek */
  1760.             lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
  1761.             write(c->feed_fd, c->buffer, FFM_PACKET_SIZE);
  1762.             
  1763.             feed->feed_write_index += FFM_PACKET_SIZE;
  1764.             /* update file size */
  1765.             if (feed->feed_write_index > c->stream->feed_size)
  1766.                 feed->feed_size = feed->feed_write_index;
  1767.  
  1768.             /* handle wrap around if max file size reached */
  1769.             if (feed->feed_write_index >= c->stream->feed_max_size)
  1770.                 feed->feed_write_index = FFM_PACKET_SIZE;
  1771.  
  1772.             /* write index */
  1773.             ffm_write_write_index(c->feed_fd, feed->feed_write_index);
  1774.  
  1775.             /* wake up any waiting connections */
  1776.             for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
  1777.                 if (c1->state == HTTPSTATE_WAIT_FEED && 
  1778.                     c1->stream->feed == c->stream->feed) {
  1779.                     c1->state = HTTPSTATE_SEND_DATA;
  1780.                 }
  1781.             }
  1782.         } else {
  1783.             /* We have a header in our hands that contains useful data */
  1784.             AVFormatContext s;
  1785.             AVInputFormat *fmt_in;
  1786.             ByteIOContext *pb = &s.pb;
  1787.             int i;
  1788.  
  1789.             memset(&s, 0, sizeof(s));
  1790.  
  1791.             url_open_buf(pb, c->buffer, c->buffer_end - c->buffer, URL_RDONLY);
  1792.             pb->buf_end = c->buffer_end;        /* ?? */
  1793.             pb->is_streamed = 1;
  1794.  
  1795.             /* use feed output format name to find corresponding input format */
  1796.             fmt_in = av_find_input_format(feed->fmt->name);
  1797.             if (!fmt_in)
  1798.                 goto fail;
  1799.  
  1800.             s.priv_data = av_mallocz(fmt_in->priv_data_size);
  1801.             if (!s.priv_data)
  1802.                 goto fail;
  1803.  
  1804.             if (fmt_in->read_header(&s, 0) < 0) {
  1805.                 av_freep(&s.priv_data);
  1806.                 goto fail;
  1807.             }
  1808.  
  1809.             /* Now we have the actual streams */
  1810.             if (s.nb_streams != feed->nb_streams) {
  1811.                 av_freep(&s.priv_data);
  1812.                 goto fail;
  1813.             }
  1814.             for (i = 0; i < s.nb_streams; i++) {
  1815.                 memcpy(&feed->streams[i]->codec, 
  1816.                        &s.streams[i]->codec, sizeof(AVCodecContext));
  1817.             } 
  1818.             av_freep(&s.priv_data);
  1819.         }
  1820.         c->buffer_ptr = c->buffer;
  1821.     }
  1822.  
  1823.     return 0;
  1824.  fail:
  1825.     c->stream->feed_opened = 0;
  1826.     close(c->feed_fd);
  1827.     return -1;
  1828. }
  1829.  
  1830. /* return the stream number in the feed */
  1831. int add_av_stream(FFStream *feed,
  1832.                   AVStream *st)
  1833. {
  1834.     AVStream *fst;
  1835.     AVCodecContext *av, *av1;
  1836.     int i;
  1837.  
  1838.     av = &st->codec;
  1839.     for(i=0;i<feed->nb_streams;i++) {
  1840.         st = feed->streams[i];
  1841.         av1 = &st->codec;
  1842.         if (av1->codec_id == av->codec_id &&
  1843.             av1->codec_type == av->codec_type &&
  1844.             av1->bit_rate == av->bit_rate) {
  1845.  
  1846.             switch(av->codec_type) {
  1847.             case CODEC_TYPE_AUDIO:
  1848.                 if (av1->channels == av->channels &&
  1849.                     av1->sample_rate == av->sample_rate)
  1850.                     goto found;
  1851.                 break;
  1852.             case CODEC_TYPE_VIDEO:
  1853.                 if (av1->width == av->width &&
  1854.                     av1->height == av->height &&
  1855.                     av1->frame_rate == av->frame_rate &&
  1856.                     av1->gop_size == av->gop_size)
  1857.                     goto found;
  1858.                 break;
  1859.             default:
  1860.                 av_abort();
  1861.             }
  1862.         }
  1863.     }
  1864.     
  1865.     fst = av_mallocz(sizeof(AVStream));
  1866.     if (!fst)
  1867.         return -1;
  1868.     fst->priv_data = av_mallocz(sizeof(FeedData));
  1869.     memcpy(&fst->codec, av, sizeof(AVCodecContext));
  1870.     feed->streams[feed->nb_streams++] = fst;
  1871.     return feed->nb_streams - 1;
  1872.  found:
  1873.     return i;
  1874. }
  1875.  
  1876. /* compute the needed AVStream for each feed */
  1877. void build_feed_streams(void)
  1878. {
  1879.     FFStream *stream, *feed;
  1880.     int i;
  1881.  
  1882.     /* gather all streams */
  1883.     for(stream = first_stream; stream != NULL; stream = stream->next) {
  1884.         feed = stream->feed;
  1885.         if (feed) {
  1886.             if (!stream->is_feed) {
  1887.                 for(i=0;i<stream->nb_streams;i++) {
  1888.                     stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
  1889.                 }
  1890.             }
  1891.         }
  1892.     }
  1893.  
  1894.     /* gather all streams */
  1895.     for(stream = first_stream; stream != NULL; stream = stream->next) {
  1896.         feed = stream->feed;
  1897.         if (feed) {
  1898.             if (stream->is_feed) {
  1899.                 for(i=0;i<stream->nb_streams;i++) {
  1900.                     stream->feed_streams[i] = i;
  1901.                 }
  1902.             }
  1903.         }
  1904.     }
  1905.  
  1906.     /* create feed files if needed */
  1907.     for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
  1908.         int fd;
  1909.  
  1910.         if (!url_exist(feed->feed_filename)) {
  1911.             AVFormatContext s1, *s = &s1;
  1912.  
  1913.             /* only write the header of the ffm file */
  1914.             if (url_fopen(&s->pb, feed->feed_filename, URL_WRONLY) < 0) {
  1915.                 fprintf(stderr, "Could not open output feed file '%s'\n",
  1916.                         feed->feed_filename);
  1917.                 exit(1);
  1918.             }
  1919.             s->oformat = feed->fmt;
  1920.             s->nb_streams = feed->nb_streams;
  1921.             for(i=0;i<s->nb_streams;i++) {
  1922.                 AVStream *st;
  1923.                 st = feed->streams[i];
  1924.                 s->streams[i] = st;
  1925.             }
  1926.             av_write_header(s);
  1927.             /* XXX: need better api */
  1928.             av_freep(&s->priv_data);
  1929.             url_fclose(&s->pb);
  1930.         }
  1931.         /* get feed size and write index */
  1932.         fd = open(feed->feed_filename, O_RDONLY);
  1933.         if (fd < 0) {
  1934.             fprintf(stderr, "Could not open output feed file '%s'\n",
  1935.                     feed->feed_filename);
  1936.             exit(1);
  1937.         }
  1938.  
  1939.         feed->feed_write_index = ffm_read_write_index(fd);
  1940.         feed->feed_size = lseek(fd, 0, SEEK_END);
  1941.         /* ensure that we do not wrap before the end of file */
  1942.         if (feed->feed_max_size < feed->feed_size)
  1943.             feed->feed_max_size = feed->feed_size;
  1944.  
  1945.         close(fd);
  1946.     }
  1947. }
  1948.  
  1949. static void get_arg(char *buf, int buf_size, const char **pp)
  1950. {
  1951.     const char *p;
  1952.     char *q;
  1953.     int quote;
  1954.  
  1955.     p = *pp;
  1956.     while (isspace(*p)) p++;
  1957.     q = buf;
  1958.     quote = 0;
  1959.     if (*p == '\"' || *p == '\'')
  1960.         quote = *p++;
  1961.     for(;;) {
  1962.         if (quote) {
  1963.             if (*p == quote)
  1964.                 break;
  1965.         } else {
  1966.             if (isspace(*p))
  1967.                 break;
  1968.         }
  1969.         if (*p == '\0')
  1970.             break;
  1971.         if ((q - buf) < buf_size - 1)
  1972.             *q++ = *p;
  1973.         p++;
  1974.     }
  1975.     *q = '\0';
  1976.     if (quote && *p == quote)
  1977.         p++;
  1978.     *pp = p;
  1979. }
  1980.  
  1981. /* add a codec and set the default parameters */
  1982. void add_codec(FFStream *stream, AVCodecContext *av)
  1983. {
  1984.     AVStream *st;
  1985.  
  1986.     /* compute default parameters */
  1987.     switch(av->codec_type) {
  1988.     case CODEC_TYPE_AUDIO:
  1989.         if (av->bit_rate == 0)
  1990.             av->bit_rate = 64000;
  1991.         if (av->sample_rate == 0)
  1992.             av->sample_rate = 22050;
  1993.         if (av->channels == 0)
  1994.             av->channels = 1;
  1995.         break;
  1996.     case CODEC_TYPE_VIDEO:
  1997.         if (av->bit_rate == 0)
  1998.             av->bit_rate = 64000;
  1999.         if (av->frame_rate == 0)
  2000.             av->frame_rate = 5 * FRAME_RATE_BASE;
  2001.         if (av->width == 0 || av->height == 0) {
  2002.             av->width = 160;
  2003.             av->height = 128;
  2004.         }
  2005.         /* Bitrate tolerance is less for streaming */
  2006.         if (av->bit_rate_tolerance == 0)
  2007.             av->bit_rate_tolerance = av->bit_rate / 4;
  2008.         if (av->qmin == 0)
  2009.             av->qmin = 3;
  2010.         if (av->qmax == 0)
  2011.             av->qmax = 31;
  2012.         if (av->max_qdiff == 0)
  2013.             av->max_qdiff = 3;
  2014.         av->qcompress = 0.5;
  2015.         av->qblur = 0.5;
  2016.  
  2017.         break;
  2018.     default:
  2019.         av_abort();
  2020.     }
  2021.  
  2022.     st = av_mallocz(sizeof(AVStream));
  2023.     if (!st)
  2024.         return;
  2025.     stream->streams[stream->nb_streams++] = st;
  2026.     memcpy(&st->codec, av, sizeof(AVCodecContext));
  2027. }
  2028.  
  2029. int opt_audio_codec(const char *arg)
  2030. {
  2031.     AVCodec *p;
  2032.  
  2033.     p = first_avcodec;
  2034.     while (p) {
  2035.         if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
  2036.             break;
  2037.         p = p->next;
  2038.     }
  2039.     if (p == NULL) {
  2040.         return CODEC_ID_NONE;
  2041.     }
  2042.  
  2043.     return p->id;
  2044. }
  2045.  
  2046. int opt_video_codec(const char *arg)
  2047. {
  2048.     AVCodec *p;
  2049.  
  2050.     p = first_avcodec;
  2051.     while (p) {
  2052.         if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
  2053.             break;
  2054.         p = p->next;
  2055.     }
  2056.     if (p == NULL) {
  2057.         return CODEC_ID_NONE;
  2058.     }
  2059.  
  2060.     return p->id;
  2061. }
  2062.  
  2063. int parse_ffconfig(const char *filename)
  2064. {
  2065.     FILE *f;
  2066.     char line[1024];
  2067.     char cmd[64];
  2068.     char arg[1024];
  2069.     const char *p;
  2070.     int val, errors, line_num;
  2071.     FFStream **last_stream, *stream, *redirect;
  2072.     FFStream **last_feed, *feed;
  2073.     AVCodecContext audio_enc, video_enc;
  2074.     int audio_id, video_id;
  2075.  
  2076.     f = fopen(filename, "r");
  2077.     if (!f) {
  2078.         perror(filename);
  2079.         return -1;
  2080.     }
  2081.     
  2082.     errors = 0;
  2083.     line_num = 0;
  2084.     first_stream = NULL;
  2085.     last_stream = &first_stream;
  2086.     first_feed = NULL;
  2087.     last_feed = &first_feed;
  2088.     stream = NULL;
  2089.     feed = NULL;
  2090.     redirect = NULL;
  2091.     audio_id = CODEC_ID_NONE;
  2092.     video_id = CODEC_ID_NONE;
  2093.     for(;;) {
  2094.         if (fgets(line, sizeof(line), f) == NULL)
  2095.             break;
  2096.         line_num++;
  2097.         p = line;
  2098.         while (isspace(*p)) 
  2099.             p++;
  2100.         if (*p == '\0' || *p == '#')
  2101.             continue;
  2102.  
  2103.         get_arg(cmd, sizeof(cmd), &p);
  2104.         
  2105.         if (!strcasecmp(cmd, "Port")) {
  2106.             get_arg(arg, sizeof(arg), &p);
  2107.             my_addr.sin_port = htons (atoi(arg));
  2108.         } else if (!strcasecmp(cmd, "BindAddress")) {
  2109.             get_arg(arg, sizeof(arg), &p);
  2110.             if (!inet_aton(arg, &my_addr.sin_addr)) {
  2111.                 fprintf(stderr, "%s:%d: Invalid IP address: %s\n", 
  2112.                         filename, line_num, arg);
  2113.                 errors++;
  2114.             }
  2115.         } else if (!strcasecmp(cmd, "MaxClients")) {
  2116.             get_arg(arg, sizeof(arg), &p);
  2117.             val = atoi(arg);
  2118.             if (val < 1 || val > HTTP_MAX_CONNECTIONS) {
  2119.                 fprintf(stderr, "%s:%d: Invalid MaxClients: %s\n", 
  2120.                         filename, line_num, arg);
  2121.                 errors++;
  2122.             } else {
  2123.                 nb_max_connections = val;
  2124.             }
  2125.         } else if (!strcasecmp(cmd, "MaxBandwidth")) {
  2126.             get_arg(arg, sizeof(arg), &p);
  2127.             val = atoi(arg);
  2128.             if (val < 10 || val > 100000) {
  2129.                 fprintf(stderr, "%s:%d: Invalid MaxBandwidth: %s\n", 
  2130.                         filename, line_num, arg);
  2131.                 errors++;
  2132.             } else {
  2133.                 nb_max_bandwidth = val;
  2134.             }
  2135.         } else if (!strcasecmp(cmd, "CustomLog")) {
  2136.             get_arg(logfilename, sizeof(logfilename), &p);
  2137.         } else if (!strcasecmp(cmd, "<Feed")) {
  2138.             /*********************************************/
  2139.             /* Feed related options */
  2140.             char *q;
  2141.             if (stream || feed) {
  2142.                 fprintf(stderr, "%s:%d: Already in a tag\n",
  2143.                         filename, line_num);
  2144.             } else {
  2145.                 feed = av_mallocz(sizeof(FFStream));
  2146.                 /* add in stream list */
  2147.                 *last_stream = feed;
  2148.                 last_stream = &feed->next;
  2149.                 /* add in feed list */
  2150.                 *last_feed = feed;
  2151.                 last_feed = &feed->next_feed;
  2152.                 
  2153.                 get_arg(feed->filename, sizeof(feed->filename), &p);
  2154.                 q = strrchr(feed->filename, '>');
  2155.                 if (*q)
  2156.                     *q = '\0';
  2157.                 feed->fmt = guess_format("ffm", NULL, NULL);
  2158.                 /* defaut feed file */
  2159.                 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
  2160.                          "/tmp/%s.ffm", feed->filename);
  2161.                 feed->feed_max_size = 5 * 1024 * 1024;
  2162.                 feed->is_feed = 1;
  2163.                 feed->feed = feed; /* self feeding :-) */
  2164.             }
  2165.         } else if (!strcasecmp(cmd, "Launch")) {
  2166.             if (feed) {
  2167.                 int i;
  2168.  
  2169.                 feed->child_argv = (char **) av_mallocz(64 * sizeof(char *));
  2170.  
  2171.                 feed->child_argv[0] = av_malloc(7);
  2172.                 strcpy(feed->child_argv[0], "ffmpeg");
  2173.  
  2174.                 for (i = 1; i < 62; i++) {
  2175.                     char argbuf[256];
  2176.  
  2177.                     get_arg(argbuf, sizeof(argbuf), &p);
  2178.                     if (!argbuf[0])
  2179.                         break;
  2180.  
  2181.                     feed->child_argv[i] = av_malloc(strlen(argbuf + 1));
  2182.                     strcpy(feed->child_argv[i], argbuf);
  2183.                 }
  2184.  
  2185.                 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
  2186.  
  2187.                 snprintf(feed->child_argv[i], 256, "http://127.0.0.1:%d/%s", 
  2188.                     ntohs(my_addr.sin_port), feed->filename);
  2189.             }
  2190.         } else if (!strcasecmp(cmd, "File")) {
  2191.             if (feed) {
  2192.                 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
  2193.             } else if (stream) {
  2194.                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
  2195.             }
  2196.         } else if (!strcasecmp(cmd, "FileMaxSize")) {
  2197.             if (feed) {
  2198.                 const char *p1;
  2199.                 double fsize;
  2200.  
  2201.                 get_arg(arg, sizeof(arg), &p);
  2202.                 p1 = arg;
  2203.                 fsize = strtod(p1, (char **)&p1);
  2204.                 switch(toupper(*p1)) {
  2205.                 case 'K':
  2206.                     fsize *= 1024;
  2207.                     break;
  2208.                 case 'M':
  2209.                     fsize *= 1024 * 1024;
  2210.                     break;
  2211.                 case 'G':
  2212.                     fsize *= 1024 * 1024 * 1024;
  2213.                     break;
  2214.                 }
  2215.                 feed->feed_max_size = (INT64)fsize;
  2216.             }
  2217.         } else if (!strcasecmp(cmd, "</Feed>")) {
  2218.             if (!feed) {
  2219.                 fprintf(stderr, "%s:%d: No corresponding <Feed> for </Feed>\n",
  2220.                         filename, line_num);
  2221.                 errors++;
  2222.             } else {
  2223.                 /* Make sure that we start out clean */
  2224.                 if (unlink(feed->feed_filename) < 0 
  2225.                     && errno != ENOENT) {
  2226.                     fprintf(stderr, "%s:%d: Unable to clean old feed file '%s': %s\n",
  2227.                         filename, line_num, feed->feed_filename, strerror(errno));
  2228.                     errors++;
  2229.                 }
  2230.             }
  2231.             feed = NULL;
  2232.         } else if (!strcasecmp(cmd, "<Stream")) {
  2233.             /*********************************************/
  2234.             /* Stream related options */
  2235.             char *q;
  2236.             if (stream || feed) {
  2237.                 fprintf(stderr, "%s:%d: Already in a tag\n",
  2238.                         filename, line_num);
  2239.             } else {
  2240.                 stream = av_mallocz(sizeof(FFStream));
  2241.                 *last_stream = stream;
  2242.                 last_stream = &stream->next;
  2243.  
  2244.                 get_arg(stream->filename, sizeof(stream->filename), &p);
  2245.                 q = strrchr(stream->filename, '>');
  2246.                 if (*q)
  2247.                     *q = '\0';
  2248.                 stream->fmt = guess_format(NULL, stream->filename, NULL);
  2249.                 memset(&audio_enc, 0, sizeof(AVCodecContext));
  2250.                 memset(&video_enc, 0, sizeof(AVCodecContext));
  2251.                 audio_id = CODEC_ID_NONE;
  2252.                 video_id = CODEC_ID_NONE;
  2253.                 if (stream->fmt) {
  2254.                     audio_id = stream->fmt->audio_codec;
  2255.                     video_id = stream->fmt->video_codec;
  2256.                 }
  2257.             }
  2258.         } else if (!strcasecmp(cmd, "Feed")) {
  2259.             get_arg(arg, sizeof(arg), &p);
  2260.             if (stream) {
  2261.                 FFStream *sfeed;
  2262.                 
  2263.                 sfeed = first_feed;
  2264.                 while (sfeed != NULL) {
  2265.                     if (!strcmp(sfeed->filename, arg))
  2266.                         break;
  2267.                     sfeed = sfeed->next_feed;
  2268.                 }
  2269.                 if (!sfeed) {
  2270.                     fprintf(stderr, "%s:%d: feed '%s' not defined\n",
  2271.                             filename, line_num, arg);
  2272.                 } else {
  2273.                     stream->feed = sfeed;
  2274.                 }
  2275.             }
  2276.         } else if (!strcasecmp(cmd, "Format")) {
  2277.             get_arg(arg, sizeof(arg), &p);
  2278.             if (!strcmp(arg, "status")) {
  2279.                 stream->stream_type = STREAM_TYPE_STATUS;
  2280.                 stream->fmt = NULL;
  2281.             } else {
  2282.                 stream->stream_type = STREAM_TYPE_LIVE;
  2283.                 /* jpeg cannot be used here, so use single frame jpeg */
  2284.                 if (!strcmp(arg, "jpeg"))
  2285.                     strcpy(arg, "singlejpeg");
  2286.                 stream->fmt = guess_format(arg, NULL, NULL);
  2287.                 if (!stream->fmt) {
  2288.                     fprintf(stderr, "%s:%d: Unknown Format: %s\n", 
  2289.                             filename, line_num, arg);
  2290.                     errors++;
  2291.                 }
  2292.             }
  2293.             if (stream->fmt) {
  2294.                 audio_id = stream->fmt->audio_codec;
  2295.                 video_id = stream->fmt->video_codec;
  2296.             }
  2297.         } else if (!strcasecmp(cmd, "FaviconURL")) {
  2298.             if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
  2299.                 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
  2300.             } else {
  2301.                 fprintf(stderr, "%s:%d: FaviconURL only permitted for status streams\n", 
  2302.                             filename, line_num);
  2303.                 errors++;
  2304.             }
  2305.         } else if (!strcasecmp(cmd, "Author")) {
  2306.             if (stream) {
  2307.                 get_arg(stream->author, sizeof(stream->author), &p);
  2308.             }
  2309.         } else if (!strcasecmp(cmd, "Comment")) {
  2310.             if (stream) {
  2311.                 get_arg(stream->comment, sizeof(stream->comment), &p);
  2312.             }
  2313.         } else if (!strcasecmp(cmd, "Copyright")) {
  2314.             if (stream) {
  2315.                 get_arg(stream->copyright, sizeof(stream->copyright), &p);
  2316.             }
  2317.         } else if (!strcasecmp(cmd, "Title")) {
  2318.             if (stream) {
  2319.                 get_arg(stream->title, sizeof(stream->title), &p);
  2320.             }
  2321.         } else if (!strcasecmp(cmd, "Preroll")) {
  2322.             get_arg(arg, sizeof(arg), &p);
  2323.             if (stream) {
  2324.                 stream->prebuffer = atoi(arg) * 1000;
  2325.             }
  2326.         } else if (!strcasecmp(cmd, "StartSendOnKey")) {
  2327.             if (stream) {
  2328.                 stream->send_on_key = 1;
  2329.             }
  2330.         } else if (!strcasecmp(cmd, "AudioCodec")) {
  2331.             get_arg(arg, sizeof(arg), &p);
  2332.             audio_id = opt_audio_codec(arg);
  2333.             if (audio_id == CODEC_ID_NONE) {
  2334.                 fprintf(stderr, "%s:%d: Unknown AudioCodec: %s\n", 
  2335.                         filename, line_num, arg);
  2336.                 errors++;
  2337.             }
  2338.         } else if (!strcasecmp(cmd, "VideoCodec")) {
  2339.             get_arg(arg, sizeof(arg), &p);
  2340.             video_id = opt_video_codec(arg);
  2341.             if (video_id == CODEC_ID_NONE) {
  2342.                 fprintf(stderr, "%s:%d: Unknown VideoCodec: %s\n", 
  2343.                         filename, line_num, arg);
  2344.                 errors++;
  2345.             }
  2346.         } else if (!strcasecmp(cmd, "MaxTime")) {
  2347.             get_arg(arg, sizeof(arg), &p);
  2348.             if (stream) {
  2349.                 stream->max_time = atoi(arg) * 1000;
  2350.             }
  2351.         } else if (!strcasecmp(cmd, "AudioBitRate")) {
  2352.             get_arg(arg, sizeof(arg), &p);
  2353.             if (stream) {
  2354.                 audio_enc.bit_rate = atoi(arg) * 1000;
  2355.             }
  2356.         } else if (!strcasecmp(cmd, "AudioChannels")) {
  2357.             get_arg(arg, sizeof(arg), &p);
  2358.             if (stream) {
  2359.                 audio_enc.channels = atoi(arg);
  2360.             }
  2361.         } else if (!strcasecmp(cmd, "AudioSampleRate")) {
  2362.             get_arg(arg, sizeof(arg), &p);
  2363.             if (stream) {
  2364.                 audio_enc.sample_rate = atoi(arg);
  2365.             }
  2366.         } else if (!strcasecmp(cmd, "VideoBitRate")) {
  2367.             get_arg(arg, sizeof(arg), &p);
  2368.             if (stream) {
  2369.                 video_enc.bit_rate = atoi(arg) * 1000;
  2370.             }
  2371.         } else if (!strcasecmp(cmd, "VideoSize")) {
  2372.             get_arg(arg, sizeof(arg), &p);
  2373.             if (stream) {
  2374.                 parse_image_size(&video_enc.width, &video_enc.height, arg);
  2375.                 if ((video_enc.width % 16) != 0 ||
  2376.                     (video_enc.height % 16) != 0) {
  2377.                     fprintf(stderr, "%s:%d: Image size must be a multiple of 16\n",
  2378.                             filename, line_num);
  2379.                     errors++;
  2380.                 }
  2381.             }
  2382.         } else if (!strcasecmp(cmd, "VideoFrameRate")) {
  2383.             get_arg(arg, sizeof(arg), &p);
  2384.             if (stream) {
  2385.                 video_enc.frame_rate = (int)(strtod(arg, NULL) * FRAME_RATE_BASE);
  2386.             }
  2387.         } else if (!strcasecmp(cmd, "VideoGopSize")) {
  2388.             get_arg(arg, sizeof(arg), &p);
  2389.             if (stream) {
  2390.                 video_enc.gop_size = atoi(arg);
  2391.             }
  2392.         } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
  2393.             if (stream) {
  2394.                 video_enc.gop_size = 1;
  2395.             }
  2396.         } else if (!strcasecmp(cmd, "VideoHighQuality")) {
  2397.             if (stream) {
  2398.                 video_enc.flags |= CODEC_FLAG_HQ;
  2399.             }
  2400.         } else if (!strcasecmp(cmd, "VideoQDiff")) {
  2401.             if (stream) {
  2402.                 video_enc.max_qdiff = atoi(arg);
  2403.                 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
  2404.                     fprintf(stderr, "%s:%d: VideoQDiff out of range\n",
  2405.                             filename, line_num);
  2406.                     errors++;
  2407.                 }
  2408.             }
  2409.         } else if (!strcasecmp(cmd, "VideoQMax")) {
  2410.             if (stream) {
  2411.                 video_enc.qmax = atoi(arg);
  2412.                 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
  2413.                     fprintf(stderr, "%s:%d: VideoQMax out of range\n",
  2414.                             filename, line_num);
  2415.                     errors++;
  2416.                 }
  2417.             }
  2418.         } else if (!strcasecmp(cmd, "VideoQMin")) {
  2419.             if (stream) {
  2420.                 video_enc.qmin = atoi(arg);
  2421.                 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
  2422.                     fprintf(stderr, "%s:%d: VideoQMin out of range\n",
  2423.                             filename, line_num);
  2424.                     errors++;
  2425.                 }
  2426.             }
  2427.         } else if (!strcasecmp(cmd, "NoVideo")) {
  2428.             video_id = CODEC_ID_NONE;
  2429.         } else if (!strcasecmp(cmd, "NoAudio")) {
  2430.             audio_id = CODEC_ID_NONE;
  2431.         } else if (!strcasecmp(cmd, "</Stream>")) {
  2432.             if (!stream) {
  2433.                 fprintf(stderr, "%s:%d: No corresponding <Stream> for </Stream>\n",
  2434.                         filename, line_num);
  2435.                 errors++;
  2436.             }
  2437.             if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
  2438.                 if (audio_id != CODEC_ID_NONE) {
  2439.                     audio_enc.codec_type = CODEC_TYPE_AUDIO;
  2440.                     audio_enc.codec_id = audio_id;
  2441.                     add_codec(stream, &audio_enc);
  2442.                 }
  2443.                 if (video_id != CODEC_ID_NONE) {
  2444.                     video_enc.codec_type = CODEC_TYPE_VIDEO;
  2445.                     video_enc.codec_id = video_id;
  2446.                     add_codec(stream, &video_enc);
  2447.                 }
  2448.             }
  2449.             stream = NULL;
  2450.         } else if (!strcasecmp(cmd, "<Redirect")) {
  2451.             /*********************************************/
  2452.             char *q;
  2453.             if (stream || feed || redirect) {
  2454.                 fprintf(stderr, "%s:%d: Already in a tag\n",
  2455.                         filename, line_num);
  2456.                 errors++;
  2457.             } else {
  2458.                 redirect = av_mallocz(sizeof(FFStream));
  2459.                 *last_stream = redirect;
  2460.                 last_stream = &redirect->next;
  2461.  
  2462.                 get_arg(redirect->filename, sizeof(redirect->filename), &p);
  2463.                 q = strrchr(redirect->filename, '>');
  2464.                 if (*q)
  2465.                     *q = '\0';
  2466.                 redirect->stream_type = STREAM_TYPE_REDIRECT;
  2467.             }
  2468.         } else if (!strcasecmp(cmd, "URL")) {
  2469.             if (redirect) {
  2470.                 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
  2471.             }
  2472.         } else if (!strcasecmp(cmd, "</Redirect>")) {
  2473.             if (!redirect) {
  2474.                 fprintf(stderr, "%s:%d: No corresponding <Redirect> for </Redirect>\n",
  2475.                         filename, line_num);
  2476.                 errors++;
  2477.             }
  2478.             if (!redirect->feed_filename[0]) {
  2479.                 fprintf(stderr, "%s:%d: No URL found for <Redirect>\n",
  2480.                         filename, line_num);
  2481.                 errors++;
  2482.             }
  2483.             redirect = NULL;
  2484.         } else {
  2485.             fprintf(stderr, "%s:%d: Incorrect keyword: '%s'\n", 
  2486.                     filename, line_num, cmd);
  2487.             errors++;
  2488.         }
  2489.     }
  2490.  
  2491.     fclose(f);
  2492.     if (errors)
  2493.         return -1;
  2494.     else
  2495.         return 0;
  2496. }
  2497.  
  2498.  
  2499. void *http_server_thread(void *arg)
  2500. {
  2501.     http_server(my_addr);
  2502.     return NULL;
  2503. }
  2504.  
  2505. #if 0
  2506. static void write_packet(FFCodec *ffenc,
  2507.                          UINT8 *buf, int size)
  2508. {
  2509.     PacketHeader hdr;
  2510.     AVCodecContext *enc = &ffenc->enc;
  2511.     UINT8 *wptr;
  2512.     mk_header(&hdr, enc, size);
  2513.     wptr = http_fifo.wptr;
  2514.     fifo_write(&http_fifo, (UINT8 *)&hdr, sizeof(hdr), &wptr);
  2515.     fifo_write(&http_fifo, buf, size, &wptr);
  2516.     /* atomic modification of wptr */
  2517.     http_fifo.wptr = wptr;
  2518.     ffenc->data_count += size;
  2519.     ffenc->avg_frame_size = ffenc->avg_frame_size * AVG_COEF + size * (1.0 - AVG_COEF);
  2520. }
  2521. #endif
  2522.  
  2523. void help(void)
  2524. {
  2525.     printf("ffserver version " FFMPEG_VERSION ", Copyright (c) 2000, 2001, 2002 Fabrice Bellard\n"
  2526.            "usage: ffserver [-L] [-h] [-f configfile]\n"
  2527.            "Hyper fast multi format Audio/Video streaming server\n"
  2528.            "\n"
  2529.            "-L            : print the LICENCE\n"
  2530.            "-h            : this help\n"
  2531.            "-f configfile : use configfile instead of /etc/ffserver.conf\n"
  2532.            );
  2533. }
  2534.  
  2535. void licence(void)
  2536. {
  2537.     printf(
  2538.     "ffserver version " FFMPEG_VERSION "\n"
  2539.     "Copyright (c) 2000, 2001, 2002 Fabrice Bellard\n"
  2540.     "This library is free software; you can redistribute it and/or\n"
  2541.     "modify it under the terms of the GNU Lesser General Public\n"
  2542.     "License as published by the Free Software Foundation; either\n"
  2543.     "version 2 of the License, or (at your option) any later version.\n"
  2544.     "\n"
  2545.     "This library is distributed in the hope that it will be useful,\n"
  2546.     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
  2547.     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
  2548.     "Lesser General Public License for more details.\n"
  2549.     "\n"
  2550.     "You should have received a copy of the GNU Lesser General Public\n"
  2551.     "License along with this library; if not, write to the Free Software\n"
  2552.     "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
  2553.     );
  2554. }
  2555.  
  2556. static void handle_child_exit(int sig)
  2557. {
  2558.     pid_t pid;
  2559.     int status;
  2560.  
  2561.     while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
  2562.         FFStream *feed;
  2563.  
  2564.         for (feed = first_feed; feed; feed = feed->next) {
  2565.             if (feed->pid == pid) {
  2566.                 int uptime = time(0) - feed->pid_start;
  2567.  
  2568.                 feed->pid = 0;
  2569.                 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
  2570.  
  2571.                 if (uptime < 30) {
  2572.                     /* Turn off any more restarts */
  2573.                     feed->child_argv = 0;
  2574.                 }    
  2575.             }
  2576.         }
  2577.     }
  2578.  
  2579.     need_to_start_children = 1;
  2580. }
  2581.  
  2582. int main(int argc, char **argv)
  2583. {
  2584.     const char *config_filename;
  2585.     int c;
  2586.     struct sigaction sigact;
  2587.  
  2588.     register_all();
  2589.  
  2590.     config_filename = "/etc/ffserver.conf";
  2591.  
  2592.     my_program_name = argv[0];
  2593.  
  2594.     for(;;) {
  2595.         c = getopt_long_only(argc, argv, "ndLh?f:", NULL, NULL);
  2596.         if (c == -1)
  2597.             break;
  2598.         switch(c) {
  2599.         case 'L':
  2600.             licence();
  2601.             exit(1);
  2602.         case '?':
  2603.         case 'h':
  2604.             help();
  2605.             exit(1);
  2606.         case 'n':
  2607.             no_launch = 1;
  2608.             break;
  2609.         case 'd':
  2610.             ffserver_debug = 1;
  2611.             break;
  2612.         case 'f':
  2613.             config_filename = optarg;
  2614.             break;
  2615.         default:
  2616.             exit(2);
  2617.         }
  2618.     }
  2619.  
  2620.     putenv("http_proxy");               /* Kill the http_proxy */
  2621.  
  2622.     /* address on which the server will handle connections */
  2623.     my_addr.sin_family = AF_INET;
  2624.     my_addr.sin_port = htons (8080);
  2625.     my_addr.sin_addr.s_addr = htonl (INADDR_ANY);
  2626.     nb_max_connections = 5;
  2627.     nb_max_bandwidth = 1000;
  2628.     first_stream = NULL;
  2629.     logfilename[0] = '\0';
  2630.  
  2631.     memset(&sigact, 0, sizeof(sigact));
  2632.     sigact.sa_handler = handle_child_exit;
  2633.     sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
  2634.     sigaction(SIGCHLD, &sigact, 0);
  2635.  
  2636.     if (parse_ffconfig(config_filename) < 0) {
  2637.         fprintf(stderr, "Incorrect config file - exiting.\n");
  2638.         exit(1);
  2639.     }
  2640.  
  2641.     build_feed_streams();
  2642.  
  2643.     /* signal init */
  2644.     signal(SIGPIPE, SIG_IGN);
  2645.  
  2646.     /* open log file if needed */
  2647.     if (logfilename[0] != '\0') {
  2648.         if (!strcmp(logfilename, "-"))
  2649.             logfile = stdout;
  2650.         else
  2651.             logfile = fopen(logfilename, "w");
  2652.     }
  2653.  
  2654.     if (http_server(my_addr) < 0) {
  2655.         fprintf(stderr, "Could not start http server\n");
  2656.         exit(1);
  2657.     }
  2658.  
  2659.     return 0;
  2660. }
  2661.